call
和
execution
的指示符分别为
call
(
Method-Signature
)、
execution
(
Method-Signature
),匹配方法签名的方法或构造函数的执行。
对于
call
来说,调用的连接点位于方法调用点的调用代码处;对于
execution
来说,执行的连接点位于方法执行的位置。也就是说,
call
和
execution
的重要区别在于它们传递了哪些类型给
AspectJ
编译器以用来与
aspect
进行链接。
通常,我们在使用
call
和
execution
时,从效果上来看并不会觉察出二者的区别。下面给出一个例子说明
call
和
execution
的运行时机及区别。
public class A {
public void foo(){
System.out.println("A.foo()");
}
}
public class Main {
public void callFoo(A a){
a.foo();
}
public static void main(String[] args) {
Main m = new Main();
m.callFoo(new A());
}
}
1
)现在我看一下下面使用
call
的切面:
该切面定义了一个切入点callA(Object
o,Object
t),其中this(o)表示将匹配的连接点的对象赋给o,target(t)表示将匹配的连接点的目标对象赋给t。输出结果为:
输出表明,this的类(调用类)为Main,target的类(目标类)为A。我们再看一下Main类:
在AJDT下,可以看到,call切入点匹配的位置在调用类(Main)的方法void
callFoo(A a)中,而不是在目标类A中。
2)再来看一下execution的例子:
在这个方面中,切入点没有使用this和target,而是在before通知中使用了AspectJ的API达到同样的效果。可以看到,切入点executionA()匹配的连接点的位置在A的foo()方法,这和上面的call匹配的连接点的位置是不同的。
从输出可以看到,在execution中,this和target指向同一个类。在call中,this和target不是指向同一个类。
execution与call还有一点很重要的区别。对于继承类来说,如果它没有覆盖父类的方法,那么execution不会匹配子类中没有覆盖父类的方法。比如说我们有一个类B继承于A,但没有覆盖A类的foo(),那么对于B的实例的foo()方法,execution(*
B.foo())将不会被匹配。
做个总结,如果想跟踪连接点的内部代码运行情况可以考虑使用execution,但如果你只关心连接点的签名(比如你使用第三方库或是标准API),则使用call。
注:该文参考了《Eclipse
AspectJ》和《AspectJ
cookbook》。