Pointcut 表示式


Pointcut 表示式用來定義斷言,用以匹配、判斷某些方法呼叫是否要織入 Advice,Spring AOP 的 Pointcut 表示式主要借鏡自 AspectJ,然而並未全部支援,可使用的代號(designator)有以下幾個:

  • execution:最主要的表示式,用來匹配方法執行的 Join Point。
  • within:必須是指定的型態,可用來取代某些 execution 模式。
  • this:代理物件必須是指定的型態,常用於 Advice 中要取得代理物件之時。
  • target:目標物件必須是指定的型態,常用於 Advice 中要取得目標物件之時。
  • args:引數必須是指定的型態,常用於 Advice 中要取得方法引數之時。。
  • @target:目標物件必須擁有指定的標型,常用於 Advice 中要取得標註之時。
  • @args:引數必須擁有指定的標註,常用於 Advice 中要取得標註之時。
  • @within:必須擁有指定的標註,常用於 Advice 中要取得標註之時。
  • @annotation:方法上必須擁有指定的標註,常用於 Advice 中要取得標註之時。

execution 是最常使用的表示式代號,可撰寫的模式為:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
          throws-pattern?)

模式中的 ? 表示選擇性設置,也就是除了 ret-type-pattern、name-pattern 與 param-pattern 為必要之外,其他都可以選擇性地設置,沒有設置的話就是不限定;必要的設置可以使用 * 表示任意符號,.. 表示 0 或多個符號,+ 表示必須是指定型態的子型態。

以先前文件中經常看到的 execution(* cc.openhome.model.AccountDAO.*(..)) 為例,它表示沒有限定權限修飾,也就是 publicprotectedprivate 或 default 方法都可以,第一個 * 設定傳回型態(ret-type-pattern)可以是任何型態,cc.openhome.model.AccountDAO.* 指定了名稱模式(name-pattern),其中的 * 表示任何方法,.. 表示任意數量引數。

來看看幾個設置的模式範例:

  • 任何公開方法

    execution(public * *(..))

  • 任何 accountBy 開頭的方法

    execution(* accountBy*(..))

  • accountBy 開頭而且有一個參數型態為 String 的方法

    execution(* accountBy*(String))

  • get 開頭而且無參數方法

    execution(* get*())

  • get 開頭而且有兩個參數的方法,第二個參數必須是 String

    execution(* get*(*,String))

  • get 開頭而且第一個參數必須是 String 的方法

    execution(* get*(String,..))

  • cc.openhome.model 套件中任何型態的方法

    execution(* cc.openhome.model.*.*(..))

  • cc.openhome.model 套件或子套件中任何型態的方法

    execution(* cc.openhome.model.service..*.*(..))

within 限定必須是指定的型態,可以使用 *..,某些 execution 模式,可以使用 within 取代,例如:

  • within(cc.openhome.model.AccountDAO) 相當於 execution(* cc.openhome.model.AccountDAO.*(..))
  • within(cc.openhome.model.*) 相當於 execution(* cc.openhome.model.*.*(..))
  • within(cc.openhome.model..*) 相當於 execution(* cc.openhome.model.service..*.*(..))

Pointcut 表示式可以使用 &&||! 來作關係運算,例如在〈定義 Introduction〉中看過:

...略    
@Around("execution(* cc.openhome.model.AccountDAO.*(..)) && this(nullable)")
public Object around(ProceedingJoinPoint proceedingJoinPoint, Nullable nullable) throws Throwable {
...略

這表示,必須是 cc.openhome.model.AccountDAO 型態上的方法,而且代理物件必須是 Nullable,因為使用了 &&,而且 this(nullable) 中的 nullable 表示,從 around 方法上與 nullable 同名的參數得知型態。

當然,如果只是想限定代理物件必須是 cc.openhome.aspect.Nullable,只要寫 this(cc.openhome.aspect.Nullable) 就可以了。

其他的代號與 this 類似,也都可以用來在 Advice 中取得對應的物件;args 若有多個引數要定義,可以使用 args(name, email) 這類的形式,或者也可以使用 args(name,..) 表示至少有一個參數。