AOP - 切點表示式

CyrusHuang發表於2024-11-02

execution 表示式

// 語法格式
execution(方法訪問修飾符? 方法返回型別 方法所在包路徑?.方法名(方法引數型別) 方法丟擲的異常?)
  1. 訪問修飾符:public、protected、private 等,可省略,省略表示任意修飾符

    // com.example.service.UserService 類中的所有 public 方法
    execution(public * com.example.service.UserService.*(..))
    
  2. 返回型別:指方法返回型別,可以是具體的類名,比如 String、void、com.example.User 等,* 表示任何型別

  3. 包路徑:可選部分,指定方法所在的類或介面的模式。可以是具體的類名、介面名或 * 表示任意包, .. 表示子包

    // 指定類下所有方法作為切點(UserService 類中的所有方法)
    execution(* com.example.service.UserService.*(..))
    
    // 指定介面所有實現類的方法作為切點(UserServiceInterface 介面的所有類中的方法)
    execution(* com.example.service.UserServiceInterface.*(..))
    
    // 指定子類所有方法作為切點(+表示 BaseService 類及其所有子類的方法)
    execution(* com.example.service.BaseService+.*(..))
    
    // 指定 com.example.service 包及其子包下所有類的方法作為切點(com.example.service 包及其子包中的所有方法)
    execution(* com.example.service..*.*(..))
    
  4. 方法名:方法名稱,* 表示任何方法

  5. 方法引數:指方法引數型別,.. 表示任意數量的引數,* 表示任意型別

    // com.example.service.UserService 類中的 addUser 方法(第一個引數為 String 型別,其餘引數可以是任意型別)
    execution(* com.example.service.UserService.addUser(String, ..))
    
    // 第一個引數為 String 型別,第二個引數為 Integer 型別,其餘引數可以是任意型別
    execution(* com.example.service.UserService.addUser(String, Integer ..))
    
  6. 異常:方法丟擲的異常,可選項

    // com.example.service.UserService 類下丟擲 Exception 的所有方法
    execution(* com.example.service.UserService.*(..) throws Exception)
    

within 表示式

execution 完全可以代替 within 的功能

*表示任意類,.. 表示子包和的所有類(..* 和 .. 是相同功能只是語義上有些許著重的意思 )

// 語法格式(指定類或包,不能具體到方法級別)
within(範圍)
  1. 匹配特定的類

    // 匹配 UserService 類中的所有方法
    within(com.example.service.UserService)
    
  2. 匹配特定的包

    // com.example.service 這個包及其子包下的所有類
    within(com.example.service..*)
    // 選擇的切點是一樣的
    within(com.example.service..)
    

@annotation 表示式

這也是比較常用的表示式,語法也比較簡單

// 標註了 @GetMapping 的方法將作為切點
@annotation(org.springframework.web.bind.annotation.GetMapping)

其他表示式

除了 execution、within、@annotation 表示式之外還有 this、target、args 表示式,不過這三種不常用

組合表示式

// AND
@Pointcut("execution(* com.example.service.*(..)) && within(com.example.service.UserService)")

// OR
@Pointcut("execution(* com.example.service.*(..)) || execution(* com.example.repository.*(..))")

// NOT
@Pointcut("execution(* com.example.service.*(..)) && !execution(* com.example.service.UserService.*(..))")

表示式示例

  • 某個特殊的方法:com.example.service.UserService 類中所有以 find 開頭的公共方法

    execution(public * com.example.service.UserService.find*(..))

  • 類中的所有方法:com.example.service 包下所有類的所有方法

    execution(* com.example.service.*.*(..))

  • 特定引數型別的方法:com.example.service.UserService 類中接受一個 User 物件作為引數的方法

    execution(String com.example.service.UserService.getName(..))

  • com.example.service 包及其子包下的所有類中的所有方法

    execution(* com.example.service..*.*(..))

  • com.example.service 包及其子包下的所有類中的所有方法

    within 不能指定某個方法,本身是類級別的;execution 可以指定某個方法

    如果exection 切某個包及其子包下所有方法就和 within 功能一樣了

    within(com.example.service..*)

  • 帶有特定註解的方法:被 @Loggable 註解標記的方法

    @annotation(com.example.annotation.Loggable)

  • 結合多個條件:匹配 com.example.service 包中所有被 @Loggable 註解標記的方法

    execution(* com.example.service.*.*(..)) && @annotation(com.example.annotation.Loggable)

  • 有異常丟擲的方法:匹配 com.example.service 包下所有方法,並且這些方法丟擲 Exception

    execution(* com.example.service.*.*(..)) throws Exception

相關文章