今天学习了一下AspectJ,查看了官方文档,查阅了很多其他技术博客,发现大部分人对关键字target、this、within之间差异不是特别清楚,所以引入本文来详细讨论它们之间的区别。特别介绍http://blog.csdn.net/zl3450341/article/details/7673979此文,本片验证思路来源于此并做了扩充说明。
1.首先,AspectJ官方怎么描述这三个关键字:
this(SomeType):when the object currently executing (i.e. this) is of type SomeType
当前执行对象是否是某种类型
target(SomeType):when the target object is of type SomeType
目标对象是否是某种类型
within(MyClass):when the executing code belongs to class MyClass
当前执行代码是否属于某个类
此处需要注意的是"对象是否是某种类型"A和“执行代码属于某个类的区别”B,描述A应该具有面向对象特性(继承)。
2.其次,关于call与execution两个关键字
execution(void Point.setX(int)):when a particular method body executes
当特定方法体执行时
call(void Point.setX(int)):when a method is called
当一个方法被调用时
此处不同的切点类型对后面使用this与within时的语义理解有影响
3.测试验证
基础类
public interface Animal
{
public void move();
}
public class Snake implements Animal
{
@Override
public void move()
{
System.out.println("snake is crawling.");
System.out.println();
}
}
public class Bird implements Animal
{
@Override
public void move()
{
System.out.println("bird is flying.");
System.out.println();
}
}
public class TestDifferentBetweenThisTargetWithin
{
private List<Animal> animals = new ArrayList<Animal>();
@Before
public void setUp()
{
animals.clear();
animals.add(new Bird());
animals.add(new Snake());
}
public void move()
{
for (Animal a : animals)
{
a.move();
}
}
@Test
public void testDifferent()
{
move();
}
}
AspectJ相关
public aspect AspectDifferent
{
pointcut moveCall():call(public void move())
pointcut moveExecution():execution(public void move())
before() :moveCall()
{
System.out.println();
System.out.println("thisJoinPoint:" + thisJoinPoint);
System.out.println("Kind:" + thisJoinPoint.getKind());
System.out.println("Target:" + thisJoinPoint.getTarget().getClass());
System.out.println("This:" + thisJoinPoint.getThis().getClass());
System.out.println("SourceLineNumber:" + thisJoinPoint.getSourceLocation());
}
before() :moveExecution()
{
System.out.println();
System.out.println("thisJoinPoint:" + thisJoinPoint);
System.out.println("Kind:" + thisJoinPoint.getKind());
System.out.println("Target:" + thisJoinPoint.getTarget().getClass());
System.out.println("This:" + thisJoinPoint.getThis().getClass());
System.out.println("SourceLineNumber:" + thisJoinPoint.getSourceLocation());
}
}
4.测试结果(有点多,看起来有点花眼,请仔细看target object与this object的信息,特别是使用call与execution对this的影响):
1 pointcut moveCall():call(public void move());拦截到的方法数为3
切点语义描述:所有调用公开的没有返回值的名为move的方法
输出结果:
thisJoinPoint:call(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-call
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Bird
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Snake
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
snake is crawling.
2 pointcut moveCall():call(public void move()) && target(Animal);方法数2
语义描述:所有调用公开的没有返回值的名为move的方法并且目标对象是Animal类型
输出结果:
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Bird
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Snake
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
snake is crawling.
3 pointcut moveCall():call(public void move()) && target(Bird);方法数1
语义描述:所有调用公开的没有返回值的名为move的方法并且目标对象是Bird类型
输出结果:
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Bird
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
snake is crawling.
4 pointcut moveCall():call(public void move()) && target(Snake);方法数1
语义描述:所有调用公开的没有返回值的名为move的方法并且目标对象是Snake类型
输出结果:
bird is flying.
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Snake
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
snake is crawling.
5 pointcut moveCall():call(public void move()) && target(TestDifferentBetweenThisTargetWithin);方法数1
语义描述:所有调用公开的没有返回值的名为move的方法并且目标对象是TestDifferentBetweenThisTargetWithin类型
输出结果:
thisJoinPoint:call(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-call
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
snake is crawling.
6 pointcut moveCall():call(public void move()) && this(Animal);方法数0
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用对象是Animal类型
输出结果:
bird is flying.
snake is crawling.
7 pointcut moveCall():call(public void move()) && this(Bird); 方法数0
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用对象是Bird类型
输出结果:
bird is flying.
snake is crawling.
8 pointcut moveCall():call(public void move()) && this(Snake);方法数0
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用对象是Snake类型
输出结果:
bird is flying.
snake is crawling.
9 pointcut moveCall():call(public void move()) && this(TestDifferentBetweenThisTargetWithin);方法数3
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用对象是TestDifferentBetweenThisTargetWithin类型
输出结果:
thisJoinPoint:call(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-call
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Bird
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Snake
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
snake is crawling.
10 pointcut moveCall():call(public void move()) && within(Animal);方法数0
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用的代码属于Animal类
输出结果:
bird is flying.
snake is crawling.
11 pointcut moveCall():call(public void move()) && within(Bird);方法数0
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用的代码属于Bird类
输出结果:
bird is flying.
snake is crawling.
12 pointcut moveCall():call(public void move()) && within(Snake);方法数0
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用的代码属于Snake类
输出结果:
bird is flying.
snake is crawling.
13 pointcut moveCall():call(public void move()) && within(TestDifferentBetweenThisTargetWithin);方法数3
语义描述:所有调用公开的没有返回值的名为move的方法并且当前执行调用的代码属于TestDifferentBetweenThisTargetWithin类
输出结果:
thisJoinPoint:call(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-call
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Bird
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
thisJoinPoint:call(void aspectJ.Animal.move())
Kind:method-call
Target:class aspectJ.Snake
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
snake is crawling.
14 pointcut moveExecution():execution(public void move());方法数3
语义描述:所有公开的没有返回值的名为move的执行方法体
输出结果:
thisJoinPoint:execution(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-execution
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
thisJoinPoint:execution(void aspectJ.Bird.move())
Kind:method-execution
Target:class aspectJ.Bird
This:class aspectJ.Bird
bird is flying.
thisJoinPoint:execution(void aspectJ.Snake.move())
Kind:method-execution
Target:class aspectJ.Snake
This:class aspectJ.Snake
snake is crawling.
15 pointcut moveExecution():execution(public void move()) && target(Animal); 方法数2
语义描述:所有公开的没有返回值的名为move的执行方法体并且目标对象是Animal
输出结果:
thisJoinPoint:execution(void aspectJ.Bird.move())
Kind:method-execution
Target:class aspectJ.Bird
This:class aspectJ.Bird
bird is flying.
thisJoinPoint:execution(void aspectJ.Snake.move())
Kind:method-execution
Target:class aspectJ.Snake
This:class aspectJ.Snake
snake is crawling.
16 pointcut moveExecution():execution(public void move()) && target(Bird); 方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且目标对象是Bird
输出结果:
thisJoinPoint:execution(void aspectJ.Bird.move())
Kind:method-execution
Target:class aspectJ.Bird
This:class aspectJ.Bird
bird is flying.
snake is crawling.
17 pointcut moveExecution():execution(public void move()) && target(Snake); 方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且目标对象是Snake
输出结果:
bird is flying.
thisJoinPoint:execution(void aspectJ.Snake.move())
Kind:method-execution
Target:class aspectJ.Snake
This:class aspectJ.Snake
snake is crawling.
18 pointcut moveExecution():execution(public void move()) && target(TestDifferentBetweenThisTargetWithin);方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且目标对象是TestDifferentBetweenThisTargetWithin
输出结果:
thisJoinPoint:execution(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-execution
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
snake is crawling.
19 pointcut moveExecution():execution(public void move()) && this(Animal);方法数2
语义描述:所有公开的没有返回值的名为move的执行方法体并且执行这个执行方法体动作的对象是Animal类型,也就是说当前实例方法体的实例主体是Animal类型
输出结果:
thisJoinPoint:execution(void aspectJ.Bird.move())
Kind:method-execution
Target:class aspectJ.Bird
This:class aspectJ.Bird
bird is flying.
thisJoinPoint:execution(void aspectJ.Snake.move())
Kind:method-execution
Target:class aspectJ.Snake
This:class aspectJ.Snake
snake is crawling.
20 pointcut moveExecution():execution(public void move()) && this(Bird);方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且执行这个执行方法体动作的对象是Bird类型,也就是说当前实例方法体的实例主体是Bird类型
输出结果:
thisJoinPoint:execution(void aspectJ.Bird.move())
Kind:method-execution
Target:class aspectJ.Bird
This:class aspectJ.Bird
bird is flying.
snake is crawling.
21 pointcut moveExecution():execution(public void move()) && this(Snake); 方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且执行这个执行方法体动作的对象是Snake类型,也就是说当前实例方法体的实例主体是Snake类型
输出结果:
bird is flying.
thisJoinPoint:execution(void aspectJ.Snake.move())
Kind:method-execution
Target:class aspectJ.Snake
This:class aspectJ.Snake
snake is crawling.
22 pointcut moveExecution():execution(public void move()) && this(TestDifferentBetweenThisTargetWithin);方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且执行这个执行方法体动作的对象是TestDifferentBetweenThisTargetWithin类型,也就是说当前实例方法体的实例主体是TestDifferentBetweenThisTargetWithin类型
输出结果:
thisJoinPoint:execution(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-execution
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
snake is crawling.
23 pointcut moveExecution():execution(public void move()) && within(Animal);方法数0
语义描述:所有公开的没有返回值的名为move的执行方法体并且这个方法体执行代码是属于Animal类
输出结果:
bird is flying.
snake is crawling.
24 pointcut moveExecution():execution(public void move()) && within(Bird); 方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且这个方法体执行代码是属于Bird类
输出结果:
thisJoinPoint:execution(void aspectJ.Bird.move())
Kind:method-execution
Target:class aspectJ.Bird
This:class aspectJ.Bird
bird is flying.
snake is crawling.
25 pointcut moveExecution():execution(public void move()) && within(Snake); 方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且这个方法体执行代码是属于Snake类
输出结果:
bird is flying.
thisJoinPoint:execution(void aspectJ.Snake.move())
Kind:method-execution
Target:class aspectJ.Snake
This:class aspectJ.Snake
snake is crawling.
26 pointcut moveExecution():execution(public void move()) && within(TestDifferentBetweenThisTargetWithin);方法数1
语义描述:所有公开的没有返回值的名为move的执行方法体并且这个方法体执行代码是属于TestDifferentBetweenThisTargetWithin类
输出结果:
thisJoinPoint:execution(void aspectJ.test.TestDifferentBetweenThisTargetWithin.move())
Kind:method-execution
Target:class aspectJ.test.TestDifferentBetweenThisTargetWithin
This:class aspectJ.test.TestDifferentBetweenThisTargetWithin
bird is flying.
snake is crawling.
5.测试结论:
无论是使用call还是execution类型pointcut,target对象均不会受影响,target可以理解为拥有move方法(move方法在某个类中定义)的实例是什么类型。(所以2,15;3,16;4,17;5,18结果相同)
使用call类型 pointcut时,this可以理解为调用move这个方法的实例是什么类型。(上面测试中所有call的this object都是TestDifferentBetweenThisTargetWithin,所以6,7,8均没有拦截到方法,9拦截数量为3)
使用execution类型 pointcut时,this可以理解为拥有move方法(move方法在某个类中定义)的实例是什么类型,与target相同(19,20,21,22)。
Target与this均支持继承(描述都是“是什么类型“),within不支持(描述是”代码属于哪个类“)。
上面测试中所有调用move方法都是TestDifferentBetweenThisTargetWithin,所以10,11,12拦截数为0, 13拦截数为3
上面测试用所有move方法的执行都是在各自类中,所以23拦截数为0, 24,25,26拦截数分别为1
以上所有欢迎讨论。