第五章、AOP細節
一、切入點表示式
切入點表示式作用:通過表示式的方式定位一個或多個具體的連線點。
#語法 execution (許可權修飾符 返回值型別 簡單類名/全類名.方法名(引數列表))
舉例說明:
#ArithmeticCalculator介面中宣告的所有方法。 execution(* com.jdy.spring2020.scan.service.impl.ArithmeticCalculatorImpl.*(..)) #第一個 “*”代表任意修飾符及任意返回值。 #第二個 “*”代表任意方法。 #“..”匹配任意數量、任意型別的引數。#若目標類、介面與該切面類在同一個包中可以省略包名。
#ArithmeticCalculator介面的所有公有方法 execution(public * ArithmeticCalculator.*(..))
在AspectJ中,切入點表示式可以通過 “&&”、“||”、“!”等操作符結合起來。
#任意類中第一個引數為int型別的add方法或sub方法 execution (* *.add(int,..)) || execution(* *.sub(int,..))
#匹配不是任意類中第一個引數為int型別的add方法!execution (* *.add(int,..))
三、通知
-
-
一個切面可以包括一個或者多個通知。
-
通知所使用的註解的值往往是切入點表示式。
3.1、前置通知
-
前置通知:在方法執行之前執行的通知。
-
使用@Before註解。
3.2、後置通知
-
後置通知:後置通知是在連線點完成之後執行的,即連線點返回結果或者丟擲異常的時候。
-
使用@After註解。
3.3、返回通知
-
返回通知:無論連線點是正常返回還是丟擲異常,後置通知都會執行。如果只想在連線點返回的時候記錄日誌,應使用返回通知代替後置通知。
-
使用@AfterReturning註解,在返回通知中訪問連線點的返回值
-
在返回通知中,只要將returning屬性新增到@AfterReturning註解中,就可以訪問連線點的返回值。該屬性的值即為用來傳入返回值的引數名稱
-
必須在通知方法的簽名中新增一個同名引數。在執行時Spring AOP會通過這個引數傳遞返回值
-
原始的切點表示式需要出現在pointcut屬性中
-
3.4、異常通知
-
異常通知:只在連線點丟擲異常時才執行異常通知
-
將throwing屬性新增到@AfterThrowing註解中,也可以訪問連線點丟擲的異常。Throwable是所有錯誤和異常類的頂級父類,所以在異常通知方法可以捕獲到任何錯誤和異常。
-
如果只對某種特殊的異常型別感興趣,可以將引數宣告為其他異常的引數型別。然後通知就只在丟擲這個型別及其子類的異常時才被執行。
3.5、環繞通知
-
環繞通知是所有通知型別中功能最為強大的,能夠全面地控制連線點,甚至可以控制是否執行連線點。
-
對於環繞通知來說,連線點的引數型別必須是ProceedingJoinPoint。它是 JoinPoint的子介面,允許控制何時執行,是否執行連線點。
-
在環繞通知中需要明確呼叫ProceedingJoinPoint的proceed()方法來執行被代理的方法。如果忘記這樣做就會導致通知被執行了,但目標方法沒有被執行。
-
注意:環繞通知的方法需要返回目標方法執行之後的結果,即呼叫 joinPoint.proceed();的返回值,否則會出現空指標異常。
四、重用切入點定義
-
在編寫AspectJ切面時,可以直接在通知註解中書寫切入點表示式。但同一個切點表示式可能會在多個通知中重複出現。
-
在AspectJ切面中,可以通過@Pointcut註解將一個切入點宣告成簡單的方法。切入點的方法體通常是空的,因為將切入點定義與應用程式邏輯混在一起是不合理的。
-
切入點方法的訪問控制符同時也控制著這個切入點的可見性。如果切入點要在多個切面中共用,最好將它們集中在一個公共的類中。在這種情況下,它們必須被宣告為public。在引入這個切入點時,必須將類名也包括在內。如果類沒有與這個切面放在同一個包中,還必須包含包名。
-
其他通知可以通過方法名稱引入該切入點
五、指定切面的優先順序
-
在同一個連線點上應用不止一個切面時,除非明確指定,否則它們的優先順序是不確定的。
-
切面的優先順序可以通過實現Ordered介面或利用@Order註解指定。
-
實現Ordered介面,getOrder()方法的返回值越小,優先順序越高。
-
若使用@Order註解,序號出現在註解中
@Component @Aspect @EnableAspectJAutoProxy(proxyTargetClass = true) @Order(0) public class CalculatorLoggingAspect {}