1. 程式人生 > 實用技巧 >第五章、AOP細節

第五章、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,..))

二、當前連線點細節

切入點表示式通常都會是從巨集觀上定位一組方法,和具體某個通知的註解結合起來就能夠確定對應的連線點。那麼就一個具體的連線點而言,我們可能會關心這個連線點的一些具體資訊,例如:當前連線點所在方法的方法名、當前傳入的引數值等等。這些資訊都封裝在JoinPoint介面的例項物件中。

2.1、JoinPoint物件

三、通知

  • 在具體的連線點上要執行的操作。

  • 一個切面可以包括一個或者多個通知。

  • 通知所使用的註解的值往往是切入點表示式。

3.1、前置通知

  1. 前置通知:在方法執行之前執行的通知。

  2. 使用@Before註解。

3.2、後置通知

  1. 後置通知:後置通知是在連線點完成之後執行的,即連線點返回結果或者丟擲異常的時候。

  2. 使用@After註解。

3.3、返回通知

  1. 返回通知:無論連線點是正常返回還是丟擲異常,後置通知都會執行。如果只想在連線點返回的時候記錄日誌,應使用返回通知代替後置通知。

  2. 使用@AfterReturning註解,在返回通知中訪問連線點的返回值

    • 在返回通知中,只要將returning屬性新增到@AfterReturning註解中,就可以訪問連線點的返回值。該屬性的值即為用來傳入返回值的引數名稱

    • 必須在通知方法的簽名中新增一個同名引數。在執行時Spring AOP會通過這個引數傳遞返回值

    • 原始的切點表示式需要出現在pointcut屬性中

3.4、異常通知

  1. 異常通知:只在連線點丟擲異常時才執行異常通知

  2. 將throwing屬性新增到@AfterThrowing註解中,也可以訪問連線點丟擲的異常。Throwable是所有錯誤和異常類的頂級父類,所以在異常通知方法可以捕獲到任何錯誤和異常。

  3. 如果只對某種特殊的異常型別感興趣,可以將引數宣告為其他異常的引數型別。然後通知就只在丟擲這個型別及其子類的異常時才被執行。

3.5、環繞通知

  1. 環繞通知是所有通知型別中功能最為強大的,能夠全面地控制連線點,甚至可以控制是否執行連線點。

  2. 對於環繞通知來說,連線點的引數型別必須是ProceedingJoinPoint。它是 JoinPoint的子介面,允許控制何時執行,是否執行連線點。

  3. 在環繞通知中需要明確呼叫ProceedingJoinPoint的proceed()方法來執行被代理的方法。如果忘記這樣做就會導致通知被執行了,但目標方法沒有被執行。

  4. 注意:環繞通知的方法需要返回目標方法執行之後的結果,即呼叫 joinPoint.proceed();的返回值,否則會出現空指標異常。

四、重用切入點定義

  1. 在編寫AspectJ切面時,可以直接在通知註解中書寫切入點表示式。但同一個切點表示式可能會在多個通知中重複出現。

  2. 在AspectJ切面中,可以通過@Pointcut註解將一個切入點宣告成簡單的方法。切入點的方法體通常是空的,因為將切入點定義與應用程式邏輯混在一起是不合理的。

  3. 切入點方法的訪問控制符同時也控制著這個切入點的可見性。如果切入點要在多個切面中共用,最好將它們集中在一個公共的類中。在這種情況下,它們必須被宣告為public。在引入這個切入點時,必須將類名也包括在內。如果類沒有與這個切面放在同一個包中,還必須包含包名。

  4. 其他通知可以通過方法名稱引入該切入點

五、指定切面的優先順序

  1. 在同一個連線點上應用不止一個切面時,除非明確指定,否則它們的優先順序是不確定的。

  2. 切面的優先順序可以通過實現Ordered介面或利用@Order註解指定。

  3. 實現Ordered介面,getOrder()方法的返回值越小,優先順序越高。

  4. 若使用@Order註解,序號出現在註解中

@Component
@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Order(0)
public class CalculatorLoggingAspect {}