天天看點

Spring Aop(三)——Pointcut表達式介紹3 Pointcut表達式介紹

标準的Aspectj Aop的pointcut的表達式類型是很豐富的,但是Spring Aop隻支援其中的9種,外加Spring Aop自己擴充的一種一共是10種類型的表達式,分别如下。

execution:一般用于指定方法的執行,用的最多。

within:指定某些類型的全部方法執行,也可用來指定一個包。

this:Spring Aop是基于代理的,生成的bean也是一個代理對象,this就是這個代理對象,當這個對象可以轉換為指定的類型時,對應的切入點就是它了,Spring Aop将生效。

target:當被代理的對象可以轉換為指定的類型時,對應的切入點就是它了,Spring Aop将生效。

args:當執行的方法的參數是指定類型時生效。

@target:當代理的目标對象上擁有指定的注解時生效。

@args:當執行的方法參數類型上擁有指定的注解時生效。

@within:與@target類似,看官方文檔和網上的說法都是@within隻需要目标對象的類或者父類上有指定的注解,則@within會生效,而@target則是必須是目标對象的類上有指定的注解。而根據筆者的測試這兩者都是隻要目标類或父類上有指定的注解即可。

@annotation:當執行的方法上擁有指定的注解時生效。

bean:當調用的方法是指定的bean的方法時生效。

execution是使用的最多的一種Pointcut表達式,表示某個方法的執行,其标準文法如下。

modifiers-pattern表示方法的通路類型,public等;ret-type-pattern表示方法的傳回值類型,如String表示傳回類型是String,“*”表示所有的傳回類型;declaring-type-pattern表示方法的聲明類,如“com.elim..*”表示com.elim包及其子包下面的所有類型;name-pattern表示方法的名稱,如“add*”表示所有以add開頭的方法名;param-pattern表示方法參數的類型,name-pattern(param-pattern)其實是一起的表示的方法集對應的參數類型,如“add()”表示不帶參數的add方法,“add(*)”表示帶一個任意類型的參數的add方法,“add(*,String)”則表示帶兩個參數,且第二個參數是String類型的add方法;throws-pattern表示異常類型;其中以問号結束的部分都是可以省略的。

1、“execution(* add())”比對所有的不帶參數的add()方法。

2、“execution(public * com.elim..*.add*(..))”比對所有com.elim包及其子包下所有類的以add開頭的所有public方法。

3、“execution(* *(..) throws Exception)”比對所有抛出Exception的方法。

within是用來指定類型的,指定類型中的所有方法将被攔截。

1、“within(com.elim.spring.aop.service.UserServiceImpl)”比對UserServiceImpl類對應對象的所有方法外部調用,而且這個對象隻能是UserServiceImpl類型,不能是其子類型。

2、“within(com.elim..*)”比對com.elim包及其子包下面所有的類的所有方法的外部調用。

Spring Aop是基于代理的,this就表示代理對象。this類型的Pointcut表達式的文法是this(type),當生成的代理對象可以轉換為type指定的類型時則表示比對。基于JDK接口的代理和基于CGLIB的代理生成的代理對象是不一樣的。

1、“this(com.elim.spring.aop.service.IUserService)”比對生成的代理對象是IUserService類型的所有方法的外部調用。

Spring Aop是基于代理的,target則表示被代理的目标對象。當被代理的目标對象可以被轉換為指定的類型時則表示比對。

1、“target(com.elim.spring.aop.service.IUserService)”則比對所有被代理的目标對象能夠轉換為IUserService類型的所有方法的外部調用。

args用來比對方法參數的。

1、“args()”比對任何不帶參數的方法。

2、“args(java.lang.String)”比對任何隻帶一個參數,而且這個參數的類型是String的方法。

3、“args(..)”帶任意參數的方法。

4、“args(java.lang.String,..)”比對帶任意個參數,但是第一個參數的類型是String的方法。

5、“args(..,java.lang.String)”比對帶任意個參數,但是最後一個參數的類型是String的方法。

@target比對當被代理的目标對象對應的類型及其父類型上擁有指定的注解時。

1、“@target(com.elim.spring.support.MyAnnotation)”比對被代理的目标對象對應的類型上擁有MyAnnotation注解時。

@args比對被調用的方法上含有參數,且對應的參數類型上擁有指定的注解的情況。

1、“@args(com.elim.spring.support.MyAnnotation)”比對方法參數類型上擁有MyAnnotation注解的方法調用。如我們有一個方法add(MyParam param)接收一個MyParam類型的參數,而MyParam這個類是擁有注解MyAnnotation的,則它可以被Pointcut表達式“@args(com.elim.spring.support.MyAnnotation)”比對上。

@within用于比對被代理的目标對象對應的類型或其父類型擁有指定的注解的情況,但隻有在調用擁有指定注解的類上的方法時才比對。

1、“@within(com.elim.spring.support.MyAnnotation)”比對被調用的方法聲明的類上擁有MyAnnotation注解的情況。比如有一個ClassA上使用了注解MyAnnotation标注,并且定義了一個方法a(),那麼在調用ClassA.a()方法時将比對該Pointcut;如果有一個ClassB上沒有MyAnnotation注解,但是它繼承自ClassA,同時它上面定義了一個方法b(),那麼在調用ClassB().b()方法時不會比對該Pointcut,但是在調用ClassB().a()時将比對該方法調用,因為a()是定義在父類型ClassA上的,且ClassA上使用了MyAnnotation注解。但是如果子類ClassB覆寫了父類ClassA的a()方法,則調用ClassB.a()方法時也不比對該Pointcut。

@annotation用于比對方法上擁有指定注解的情況。

1、“@annotation(com.elim.spring.support.MyAnnotation)”比對所有的方法上擁有MyAnnotation注解的方法外部調用。

bean用于比對當調用的是指定的Spring的某個bean的方法時。

1、“bean(abc)”比對Spring Bean容器中id或name為abc的bean的方法調用。

2、“bean(user*)”比對所有id或name為以user開頭的bean的方法調用。

表達式的組合其實就是對應的表達式的邏輯運算,與、或、非。可以通過它們把多個表達式組合在一起。

1、“bean(userService) && args()”比對id或name為userService的bean的所有無參方法。

2、“bean(userService) || @annotation(MyAnnotation)”比對id或name為userService的bean的方法調用,或者是方法上使用了MyAnnotation注解的方法調用。

3、“bean(userService) && !args()”比對id或name為userService的bean的所有有參方法調用。

在使用基于Aspectj注解的Spring Aop時,我們可以把通過@Pointcut注解定義Pointcut,指定其表達式,然後在需要使用Pointcut表達式的時候直接指定Pointcut。

上面的代碼中我們就是在@Before()中直接指定使用目前類定義的beforeAdd()方法對應的Pointcut的表達式,如果我們需要指定的Pointcut定義不是在目前類中的,我們需要加上類名稱,如下面這個示例中引用的就是定義在MyService中的add()方法上的Pointcut的表達式。

當然了,除了通過引用Pointcut定義間接的引用其對應的Pointcut表達式外,我們也可以直接使用Pointcut表達式的,如下面這個示例就直接在@Before中使用了Pointcut表達式。

(注:本文是基于Spring4.1.0所寫,寫于2017年1月14日星期六)