10、SSM框架-Spring AOP之基於註解的宣告式AspectJ(10)
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風格的切面並且將切面應用到目標物件。<!-- 啟動@AspectJ支援 --> <!-- proxy-target-class預設"false",更改為"ture"使用CGLib動態代理 --> <aop:aspectj-autoproxy proxy-target-class="false"/>
1.2、 宣告切面
@AspectJ風格的宣告切面非常簡單,使用@Aspect註解進行宣告:
- @Aspect
- ublic class AdivceMethod {
- @Aspect
- ublic class AdivceMethod {
@Aspect
public class AdivceMethod {
然後將該切面在配置檔案中宣告為Bean後,Spring就能自動識別並進行AOP方面的配置:
[html]- <bean id="aspect" class="……AdivceMethod"/>
- <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(……) {}
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) {}
@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 = "引數列表引數名")
@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="返回值對應引數名")
@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="異常對應引數名")
@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;
@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;
- /**
- *功能 人的介面類
- *作者 林炳文([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);
- }
- 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);
- }
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;
- /**
- *功能 人的實現類
- *作者 林炳文([email protected] 部落格:http://blog.csdn.net/evankaka)
- *時間 2015.4.27
- */
- @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;
- }
- }
- 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("記錄每天喝的飲料容量");
- }
- }
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?