引貼:java
Aspectj與Spring AOP比較
AspectJ語法詳解
Spring中的AOP(五)——在Advice方法中獲取目標方法的參數spring
//定義切面 public class SleepHelperAspect{ public void beforeSleep(){ System.out.println("睡覺前要脫衣服!"); } public void afterSleep(){ System.out.println("起牀後要穿衣服!"); } }
<bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect"></bean> <aop:aspectj-autoproxy/> <aop:config> <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/> <aop:aspect ref="sleepHelperAspect"> <!--前置通知--> <aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/> <!--後置通知--> <aop:after method="afterSleep" pointcut-ref="sleepPointcut"/> </aop:aspect> </aop:config>
//定義通知 public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("睡覺前要脫衣服!"); } @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("起牀後要穿衣服!"); } }
<bean id="sleepHelper" class="com.noob.aop.SleepHelper"></bean> <aop:aspectj-autoproxy/> <aop:config> <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/> <aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/> </aop:config>
表示式(expression)和簽名(signature)express
//Pointcut表示式 @Pointcut("execution(* com.savage.aop.MessageSender.*(..))") //Point簽名 private void log(){}
由下列方式來定義或者經過 &&、 ||、 !、 的方式進行組合:框架
execution:用於匹配方法執行的鏈接點;ide
within:用於匹配指定類型內的方法執行;this
this:用於匹配當前AOP代理對象類型的執行方法;注意是AOP代理對象的類型匹配,這樣就可能包括引入接口也類型匹配; spa
target:用於匹配當前目標對象類型的執行方法;注意是目標對象的類型匹配,這樣就不包括引入接口也類型匹配;.net
args:用於匹配當前執行的方法傳入的參數爲指定類型的執行方法;3d
@within:用於匹配因此持有指定註解類型內的方法;代理
@target:用於匹配當前目標對象類型的執行方法,其中目標對象持有指定的註解;
@args:用於匹配當前執行的方法傳入的參數持有指定註解的執行;
@annotation:用於匹配當前執行方法持有指定註解的方法;
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
其中後面跟着「?」的是可選項
括號中各個pattern分別表示:
eg.
- 任意公共方法的執行:execution(public * *(..))
- 任何一個以「set」開始的方法的執行:execution(* set*(..))
- AccountService 接口的任意方法的執行:execution(* com.xyz.service.AccountService.*(..))
- 定義在service包裏的任意方法的執行: execution(* com.xyz.service.*.*(..))
- 定義在service包和全部子包裏的任意類的任意方法的執行:execution(* com.xyz.service..*.*(..))
第一個*表示匹配任意的方法返回值, ..(兩個點)表示零個或多個,第一個..表示service包及其子包,第二個*表示全部類, 第三個*表示全部方法,第二個..表示方法的任意參數個數- 定義在pointcutexp包和全部子包裏的JoinPointObjP2類的任意方法的執行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
- pointcutexp包裏的任意類: within(com.test.spring.aop.pointcutexp.*)
- pointcutexp包和全部子包裏的任意類:within(com.test.spring.aop.pointcutexp..*)
- 實現了Intf接口的全部類,若是Intf不是接口,限定Intf單個類:this(com.test.spring.aop.pointcutexp.Intf)
當一個實現了接口的類被AOP的時候,用getBean方法必須cast爲接口類型,不能爲該類的類型- 帶有@Transactional標註的全部類的任意方法:
- @within(org.springframework.transaction.annotation.Transactional)
- @target(org.springframework.transaction.annotation.Transactional)
- 帶有@Transactional標註的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)
@within和@target針對類的註解,@annotation是針對方法的註解- 參數帶有@Transactional標註的方法:@args(org.springframework.transaction.annotation.Transactional)
- 參數爲String類型(運行是決定)的方法: args(String)
當使用@Around處理時,須要將第一個參數定義爲ProceedingJoinPoint類型,該類是JoinPoint的子類。
經常使用的方法:
@AfterReturning( pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)", returning="returnValue") public void access(Date time, Object returnValue, String name) { System.out.println("目標方法中的參數String = " + name); System.out.println("目標方法中的參數Date = " + time); System.out.println("目標方法的返回結果returnValue = " + returnValue); }
表達式中增長了args(time, name)部分,意味着能夠在加強處理的簽名方法(access方法)中定義"time"和"name"兩個同名屬性。
這兩個形參的類型由access方法同名參數類型指定,一旦指定了, 則這兩個形參類型將用於限制該切入點只匹配第一個參數類型爲Date,第二個參數類型爲String的方法(方法參數個數和類型如有不一樣均不匹配);
access方法只須要知足"time", "name"參數的順序和pointcut中args(time, name)的順序相同便可,"returnValue"位置順序無所謂。
eg.
//將被access方法匹配 public String accessAdvice(Date d, String n) { System.out.println("方法:accessAdvice"); return "aa"; }
正常:
異常:
優先級高的切面類裏的加強處理的優先級老是比優先級低的切面類中的加強處理的優先級高。
在「進入」鏈接點時,最高優先級的加強處理將先被織入(eg.給定的兩個不一樣切面類Before加強處理中,優先級高的那個會先執行);在「退出」鏈接點時,最高優先級的加強處理會最後被織入(eg.給定的兩個不一樣切面類After加強處理中,優先級高的那個會後執行)。
eg.
優先級爲1的切面類Bean1包含了@Before,優先級爲2的切面類Bean2包含了@Around,雖然@Around優先級高於@Before,但因爲Bean1的優先級高於Bean2的優先級,所以Bean1中的@Before先被織入。
Spring提供了以下兩種解決方案指定不一樣切面類裏的加強處理的優先級:
同一個切面類裏的兩個相同類型的加強處理在同一個鏈接點被織入時,Spring AOP將以隨機的順序來織入這兩個加強處理,沒有辦法指定它們的織入順序。即便給這兩個 advice 添加了 @Order 這個註解,也不行!