Spring AOP 切點指示符中execution和args的區別

一、簡單介紹  

       Spring AOP中支持的切點指示符(PCD)有以下:execution、within、this、target、args、@target、@args、@within、@annotation和bean。

Spring 官網的介紹:

execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.(用於匹配方法執行的連接點。 這是使用Spring AOP時要使用的主要切入點指示符)

args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.(將匹配限制爲連接點(使用Spring AOP時方法的執行),其中參數是給定類型的實例)

通常情況下,兩者很容易使用和區分,比如:

1、表示任意public 方法的執行:

execution(public * *(..))

2、任何只有單個參數且在運行時傳遞的參數是Param實例方法的執行(注意Param要帶上包路徑):

args(com.dxc.opentalk.springtest.param.Param)

 

二、區分示例

官網給出一個例子,如下:

args(java.io.Serializable)
execution(**(java.io.Serializable))

這上面兩個切點表達式有什麼區別呢?如下:

       Note that the pointcut given in this example is different from execution(* *(java.io.Serializable)). The args version matches if the argument passed at runtime is Serializable, and the execution version matches if the method signature declares a single parameter of type Serializable.

       個人理解args(java.io.Serializable)匹配的是隻有單個入參而且入參是可以序列化(實現Serializable接口或者Serializable的子接口)的方法;而execution(* *(java.io.Serializable))匹配的是隻有單個入參而且入參聲明的必須是Serializable接口(不能是該接口的實現類以及子接口,嚴格的參數類型匹配)

三 、代碼驗證

定義一個類A,其三個方法爲連接點:

@Component
public class A {


    public void testOne(Param param) {
        System.out.println("testOne exec..." + param.getName());
    }

    public void testTwo(java.io.Serializable serializable) {
        System.out.println("testTwo exec..." + serializable.toString());
    }

    public void testThree(com.dxc.opentalk.springtest.service.TestInterface testInterface) {
        System.out.println("testThree exec..." + testInterface.toString());
    }
}

定義切面、切點以及通知:

@Aspect
@Component
public class AopConfig {

    @Pointcut("args(java.io.Serializable)")
    private void apply(){}

    @Before("apply()")
    public void check(){
        System.out.println("aop args()...");
    }

}

定義一個繼承java.io.Serializable接口的TestInterface子接口,一個參數類Param 實現java.io.Serializable接口,一個ParamOne類實現TestInterface子接口:

public interface TestInterface extends Serializable {

    void test();
}

public class Param implements Serializable {
    private static final long serialVersionUID = 1342018181486589136L;

    private String name;

    public Param(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

public class ParamOne implements TestInterface {
    private static final long serialVersionUID = 3558001836605280932L;

    public void test() {
        System.out.println("extended interface exec...");
    }

    private String name;

    public ParamOne(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

主程序類:

@EnableAspectJAutoProxy
@ComponentScan("com.dxc.opentalk.springtest")
public class BootStrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(BootStrap.class);
        A a = (A) applicationContext.getBean("a");
        a.testOne(new Param("param"));
        a.testTwo(new ArrayList());
        a.testThree(new ParamOne("paramOne"));
    }
}

當採用 @Pointcut("args(java.io.Serializable)") 時,程序輸出結果:

aop args()...
testOne exec...param
aop args()...
testTwo exec...[]
aop args()...
testThree [email protected]

可以看到,A類中的三個連接點方法全部被切點匹配上了。

 

當採用@Pointcut("execution(* *(java.io.Serializable))")時,程序輸出結果:

testOne exec...param
aop args()...
testTwo exec...[]
testThree [email protected]

可以看到,只有入參聲明是Serializable 的第二個方法void testTwo(java.io.Serializable serializable)被切點匹配上。

四、小結

     execution表達式的標準格式如下:

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

       綜上,execution表達式中的param-pattern是嚴格的類型匹配(必須是方法聲明的參數類型,子類也不可以);args表達式參數是給定類型的實例即可匹配到。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章