target
切入点格式如下:
target
([
Type
|
Identifier
])。
Type
指示对连接点处的对象类型提供一个静态编译时评估,并采用完全限定类名的形式(也就是说,
Type
不能是使用通配符的类型声明模式)。
Identifier
提供了一种方法,可通过它来评估连节点处的运行时对象的实际类型,而不仅仅是静态类型。
Identifier
在运行时动态地赋予合适的对象。
下面通过例子说明一下
target
的使用:
public
interface
Animal {
void
speak();
}
public
class
Cat
implements
Animal{
public
void
speak() {
System.
out
.println(
"
喵喵
"
);
}
}
public
class
Dog
implements
Animal{
public
void
speak() {
System.
out
.println(
"
汪汪
"
);
}
}
public
class
Zoo {
private
List<Animal>
animals
=
new
ArrayList<Animal>();
public
void
addAnimal(Animal a){
animals
.add(a);
}
public
void
speak(){
for
(Animal
a :
animals
){
a.speak();
}
}
}
定义一个切入点如下:
public
pointcut
speakCallOne():
call
(*
speak()) &&
target
(Animal);
虽然
pointcut
speakCallOne()
中的
call
(*
speak())
匹配所有类的
speak()
方法(这里匹配
Cat
、
Dog
、
Zoo
),但
target
(Animal)
便将
pointcut
speakCallOne()
限定在
Animal
及其子类(也就是
Cat
、
Dog
,而不包含
Zoo
)。这里当然可以使用
call
(*
Animal.speak())
来代替
target
。和静态的类型声明不同,
target
并不能静态地确定的每一个连接点,因为匹配是基于运行时的类型信息。在使用
AJDT
的情况下,可以看到
target
和静态的类型声明的不同:
1)使用
静态的类型声明的图示:
可以看到,在方面AspectDemo中,before通知的左面有一个向上的小箭头表示其为通知,而Zoo中的void speak()方法中a.speak();一行的左面有个向右的小箭头,表明其匹配了一个通知(也就是AspectDemo中的before通知)。
2)使用
target的图示:
和静态的类型声明不同,使用了target的before前的箭头上有个问号,以表明target动态的不确定性。而Zoo的main中调用的方法z.speak()前有个类似于speak()中的a.speak();的箭头,不同的是,z.speak()前的箭头上有个问号,这表明此处speak()并不确定是否匹配通知(因为target是动态确定连接点)。而实际上情况是,z.speak()确实不是通知的连接点。
对于target(Identifier)的使用,示例如下:
publicpointcut
speakCallTwo(Object o):
call(*
Animal.speak()) && target(o);
before(Object
o):speakCallTwo(o){
System.out.println(o.getClass());
}
}
通过将
target付给
Object
o,可以在before通知中调用
o的一些操作。
this是target指示符的一个补充,它的格式与target相同。在含义上,this表示切入点所匹配的方法的调用类,而target表示匹配方法的目标类。例如:
publicpointcut
anotherSpeakCall():
call(*
speak()) && target(Animal)
&& this(Zoo);
target(Animal)
表示void
speak()方法是Animal及子类的,它不会匹配
Zoo的void
speak()方法。而this(Zoo)会匹配调用了Animal及子类的void
speak()方法的
Zoo类的方法,这里就是Zoo的void
speak()方法。
如上便是关于target和this的基本用法。该文参考了《Eclipse
AspectJ》和《AspectJ
cookbook》。