spring除了支援Schema方式配置AOP,還支援注解方式:使用@AspectJ風格的切面聲明。導入需要的包:aspectjweaver.jar、aopalliance-1.0.jar
本文工程免費下載下傳
一、基本使用方法
1.1、啟用對@AspectJ的支援
Spring預設不支援@AspectJ風格的切面聲明,為了支援需要使用如下配置:
[java] view plain copy print ?
- <!-- 啟動@AspectJ支援 -->
- <!-- proxy-target-class預設"false",更改為"ture"使用CGLib動态代理 -->
- <aop:aspectj-autoproxy proxy-target-class="false"/>
<!-- 啟動@AspectJ支援 -->
<!-- proxy-target-class預設"false",更改為"ture"使用CGLib動态代理 -->
<aop:aspectj-autoproxy proxy-target-class="false"/>
這樣Spring就能發現@AspectJ風格的切面并且将切面應用到目标對象。
1.2、 聲明切面
@AspectJ風格的聲明切面非常簡單,使用@Aspect注解進行聲明:
[java] view plain copy print ?
- @Aspect
- ublic class AdivceMethod {
@Aspect
public class AdivceMethod {
然後将該切面在配置檔案中聲明為Bean後,Spring就能自動識别并進行AOP方面的配置:
[html] view plain copy print ?
- <bean id="aspect" class="……AdivceMethod"/>
<bean id="aspect" class="……AdivceMethod"/>
或者直接使用元注解的方法:
[java] view plain copy print ?
- @Component
- @Aspect
- public class AdivceMethod {
1.3、 聲明切入點
@AspectJ風格的命名切入點使用org.aspectj.lang.annotation包下的@Pointcut+方法(方法必須是傳回void類型)實作。
[java] view plain copy print ?
- @Pointcut(value="切入點表達式", argNames = "參數名清單")
- public void pointcutName(……) {}
value:指定切入點表達式;
argNames:指定命名切入點方法參數清單參數名字,可以有多個用“,”分隔,這些參數将傳遞給通知方法同名的參數,同時比如切入點表達式“args(param)”将比對參數類型為命名切入點方法同名參數指定的參數類型。
pointcutName:切入點名字,可以使用該名字進行引用該切入點表達式。
[java] view plain copy print ?
- @Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
- public void beforePointcut(String param) {}
@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
public void beforePointcut(String param) {}
定義了一個切入點,名字為“beforePointcut”,該切入點将比對目标方法的第一個參數類型為通知方法實作中參數名為“param”的參數類型。
二、聲明通知
@AspectJ風格的聲明通知也支援5種通知類型:
2.1、前置通知:使用org.aspectj.lang.annotation 包下的@Before注解聲明;
[java] view plain copy print ?
- @Before(value = "切入點表達式或命名切入點", argNames = "參數清單參數名")
@Before(value = "切入點表達式或命名切入點", argNames = "參數清單參數名")
value:指定切入點表達式或命名切入點;
argNames:與Schema方式配置中的同義。
接下來示例一下吧:
1、定義接口和實作,在此我們就使用Schema風格時的定義;
2、定義切面:
3、定義切入點:
4、定義通知:
2.2、後置傳回通知:使用org.aspectj.lang.annotation 包下的@AfterReturning注解聲明;
[html] view plain copy print ?
- @AfterReturning(
- value="切入點表達式或命名切入點",
- pointcut="切入點表達式或命名切入點",
- argNames="參數清單參數名",
- returning="傳回值對應參數名")
@AfterReturning(
value="切入點表達式或命名切入點",
pointcut="切入點表達式或命名切入點",
argNames="參數清單參數名",
returning="傳回值對應參數名")
value:指定切入點表達式或命名切入點;
pointcut:同樣是指定切入點表達式或命名切入點,如果指定了将覆寫value屬性指定的,pointcut具有高優先級;
argNames:與Schema方式配置中的同義;
returning:與Schema方式配置中的同義。
2.3、後置異常通知:使用org.aspectj.lang.annotation 包下的@AfterThrowing注解聲明;
[html] view plain copy print ?
- @AfterThrowing (
- value="切入點表達式或命名切入點",
- pointcut="切入點表達式或命名切入點",
- argNames="參數清單參數名",
- throwing="異常對應參數名")
@AfterThrowing (
value="切入點表達式或命名切入點",
pointcut="切入點表達式或命名切入點",
argNames="參數清單參數名",
throwing="異常對應參數名")
value:指定切入點表達式或命名切入點;
pointcut:同樣是指定切入點表達式或命名切入點,如果指定了将覆寫value屬性指定的,pointcut具有高優先級;
argNames:與Schema方式配置中的同義;
throwing:與Schema方式配置中的同義。
其中測試代碼與Schema方式幾乎一樣,在此就不示範了,如果需要請參考AopTest.Java中的testAnnotationAfterThrowingAdvice測試方法。
2.4、後置最終通知:使用org.aspectj.lang.annotation 包下的@After注解聲明;
[html] view plain copy print ?
- @After (
- value="切入點表達式或命名切入點",
- argNames="參數清單參數名")
value:指定切入點表達式或命名切入點;
argNames:與Schema方式配置中的同義;
2.5、環繞通知:使用org.aspectj.lang.annotation 包下的@Around注解聲明;
[html] view plain copy print ?
- @Around (
- value="切入點表達式或命名切入點",
- argNames="參數清單參數名")
value:指定切入點表達式或命名切入點;
argNames:與Schema方式配置中的同義;
2.6 引入
@AspectJ風格的引入聲明在切面中使用org.aspectj.lang.annotation包下的@DeclareParents聲明:
[html] view plain copy print ?
- @DeclareParents(
- value=" AspectJ文法類型表達式",
- defaultImpl=引入接口的預設實作類)
- private Interface interface;
@DeclareParents(
value=" AspectJ文法類型表達式",
defaultImpl=引入接口的預設實作類)
private Interface interface;
value:比對需要引入接口的目标對象的AspectJ文法類型表達式;與Schema方式中的types-matching屬性同義;
private Interface interface:指定需要引入的接口;
defaultImpl:指定引入接口的預設實作類,沒有與Schema方式中的delegate-ref屬性同義的定義方式;
三、使用範例
整個工程目錄如下:
本文工程免費下載下傳
記得導入包:aopalliance-1.0.jar+aspectjweaver.jar+commons-logging-1.2.jar+spring
1、首先建立一個人的接口類:
[java] view plain copy print ?
- package com.mucfu.aspectj;
- public interface Person {
- public void eatBreakfast();
- public void eatLunch();
- public void eatSupper();
- public String drink(String name);
- }
package com.mucfu.aspectj;
/**
*功能 人的接口類
*作者 林炳文([email protected] 部落格:http://blog.csdn.net/evankaka)
*時間 2015.4.27
*/
public interface Person {
public void eatBreakfast();
public void eatLunch();
public void eatSupper();
public String drink(String name);
}
2、來個baby的實作類:
[java] view plain copy print ?
- package com.mucfu.aspectj;
- import org.springframework.stereotype.Component;
- @Component
- public class BabyPerson implements Person{
- @Override
- public void eatBreakfast() {
- System.out.println("小Baby正在吃早餐");
- }
- @Override
- public void eatLunch() {
- System.out.println("小Baby正在吃午餐");
- }
- @Override
- public void eatSupper() {
- System.out.println("小Baby正在吃晚餐");
- }
- @Override
- public String drink(String name) {
- return "小Baby在喝:"+name;
- }
- }
3、然後後就是對Bayby吃飯的函數進行各種增強
[java] view plain copy print ?
- package com.mucfu.aspectj;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.springframework.stereotype.Component;
- @Component
- @Aspect
- public class AdivceMethod {
- @Before("execution(* com.mucfu.aspectj.BabyPerson.*(..))")
- // 比對BabyPerson類所有的方法,注意*和com之間有個空格
- public void beforeEat() {
- System.out
- .println("-------------------這裡是前置增強,吃飯之前先洗小手!--------------------");
- }
- @After("execution(* eatLunch(..))")
- // 比對該工程下所有的eatLunch方法
- public void afterEat() {
- System.out
- .println("-------------------這裡是後置增強,午飯吃完要睡午覺!--------------------");
- }
- @Around("execution(* com.mucfu.aspectj.BabyPerson.eatSupper())")
- // 比對該工程下BabyPerson的eatLunch方法
- public Object aroundEat(ProceedingJoinPoint pjp) throws Throwable {
- System.out
- .println("-------------------這裡是環繞增強,吃晚飯前先玩一玩!-------------------");
- Object retVal = pjp.proceed();
- System.out
- .println("-------------------這裡是環繞增強,晚飯吃完後要得睡覺了!-------------------");
- return retVal;
- }
- @AfterReturning(returning="rvt",pointcut="execution(* com.mucfu.aspectj.BabyPerson.drink(..))")
- public void log(Object rvt) {
- System.out
- .println("-------------------這裡是AfterReturning增強-------------------");
- System.out.println("擷取小Baby正在喝的飲料"+rvt);
- System.out.println("記錄每天喝的飲料容量");
- }
- }
package com.mucfu.aspectj;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AdivceMethod {
@Before("execution(* com.mucfu.aspectj.BabyPerson.*(..))")
// 比對BabyPerson類所有的方法,注意*和com之間有個空格
public void beforeEat() {
System.out
.println("-------------------這裡是前置增強,吃飯之前先洗小手!--------------------");
}
@After("execution(* eatLunch(..))")
// 比對該工程下所有的eatLunch方法
public void afterEat() {
System.out
.println("-------------------這裡是後置增強,午飯吃完要睡午覺!--------------------");
}
@Around("execution(* com.mucfu.aspectj.BabyPerson.eatSupper())")
// 比對該工程下BabyPerson的eatLunch方法
public Object aroundEat(ProceedingJoinPoint pjp) throws Throwable {
System.out
.println("-------------------這裡是環繞增強,吃晚飯前先玩一玩!-------------------");
Object retVal = pjp.proceed();
System.out
.println("-------------------這裡是環繞增強,晚飯吃完後要得睡覺了!-------------------");
return retVal;
}
@AfterReturning(returning="rvt",pointcut="execution(* com.mucfu.aspectj.BabyPerson.drink(..))")
public void log(Object rvt) {
System.out
.println("-------------------這裡是AfterReturning增強-------------------");
System.out.println("擷取小Baby正在喝的飲料"+rvt);
System.out.println("記錄每天喝的飲料容量");
}
}
4、建立一個beans.xml,内容如下:
[html] view plain copy print ?
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <!-- 指定自動搜尋bean元件、自動搜尋切面類 -->
- <context:component-scan base-package="com.mucfu"/>
- <!-- 啟動@AspectJ支援 -->
- <!-- proxy-target-class預設"false",更改為"ture"使用CGLib動态代理 -->
- <aop:aspectj-autoproxy proxy-target-class="false"/>
- </beans>
5、最後來測試
[java] view plain copy print ?
- package com.mucfu.aspectj;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class Test {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
- Person person=(Person)context.getBean("babyPerson");
- person.eatBreakfast();
- System.out.println("===================================================");
- person.eatLunch();
- System.out.println("===================================================");
- person.eatSupper();
- System.out.println("===================================================");
- person.drink("可樂");
- System.out.println("===================================================");
- }
- }
輸出結果: