AspectJ——切入点语法之捕获属性上的连接点
Posted KLeonard
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AspectJ——切入点语法之捕获属性上的连接点相关的知识,希望对你有一定的参考价值。
捕获属性上的连接点
AspectJ提供了get(Signature)
和set(Signature)
切入点的形式,来捕获可能发生在类属性上的任何访问和修改。这也是AspectJ的一个比较受争议的特性,因为它会有效地破坏类的封装性,特别是当把被监视的属性声明为protected
或者private
时。
所以这两个属性可以提供强大的手段来通知类,但是必须小心地使用它们。
0.捕获对属性的访问
我们使用get(Signature)
切入点来捕获对对象属性的访问。切入点的语法如下:
pointcut [切入点名字](想要捕获的参数): get(<可选的修饰符> 属性类型 类名.属性名)
需要注意的几点是:
get(Signature)
切入点会捕获对属性的直接访问,不仅仅只会捕获对属性getter
访问器方法的调用。get(Signature)
切入点不能捕获对常量的访问。Signature
必须解析成特定类的属性。Signature
可以包含通配符,用于选择不同属性上的一系列连接点。
我们在Test7
包下做一个简单的测试。首先新建业务类Service
:
package Test7;
public class Service
protected static String name = "Gavin John";
public static final String nickname = "GG";
private String firstname = "Gavin";
private String lastname = "John";
public String getFirstname()
return firstname;
public void setFirstname(String firstname)
this.firstname = firstname;
public String getLastname()
return lastname;
public void setLastname(String lastname)
this.lastname = lastname;
可以看到,在Service
类中,我们首先定义了静态的name
属性,接着使用static final
定义了常量nickname
,然后又定义两个普通的变量firstname
和lastname
,并且为两个普通的变量提供了getter
和setter
方法。
接着我们定义Main
主方法类,在主方法中访问这些变量:
package Test7;
public class Main
public static void main(String[] args)
Service service = new Service();
System.out.println("service.getFirstname(): " + service.getFirstname());
System.out.println("service.getLastname(): " + service.getLastname());
System.out.println("Service.name: " + Service.name);
System.out.println("Service.nickname: " + Service.nickname);
如果我们不添加切面,此时的运行结果显而易见,如下:
接着,我们添加切面FieldAspect
,如下:
package Test7;
public aspect FieldAspect
pointcut getNamePointcut(): get(String Service.*name);
before():getNamePointcut()
System.out.println();
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
在该切面中,我们使用get(Signature)
,并通过通配符定义了访问Service
类中的以name
结尾的属性切入点。
此时运行结果如下:
从运行结果中可以看出,除了对nickname
属性的访问之外,对其他属性的访问都被捕获到。nickname
是一个通过static final
定义的常量,因为编译器对常量的编译特性,AspectJ无法捕获对常量的访问。
而我们对firstname
和lastname
属性的访问是通过其getter
方法,而对name
静态属性访问是直接通过属性名字访问,这两种访问形式都被切入点捕获到。
1.获取访问的属性值
我们不仅可以捕获对属性的访问,还能获取所访问的属性值。这就要通过after() returning(<ReturnValue>)
形式的通知,它在声明的returning()
部分中带有一个标识符,用于包含访问过的值。
比如,我们简单修改上例中的切面,将其中的before()
前置通知,改为after() returning(<ReturnValue>)
形式的后置通知,如下:
package Test7;
public aspect FieldAspect
pointcut getNamePointcut(): get(String Service.*name);
after() returning(String value):getNamePointcut()
System.out.println();
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
System.out.println("访问的属性值是:" + value);
此时运行结果是:
可以看到,我们在通知中获取到了访问的属性值。
2.捕获对属性的修改
我们使用set(Signature)
切入点来捕获对对象属性的修改。其语法是:
pointcut [切入点名字](要获取的参数): set(<可选的修饰符> 属性类型 类名.属性名)
需要注意的几点是:
set(Signature)
切入点在修改属性时触发。Signature
必须解析成特定类的属性。Signature
可以包含通配符,用于选择不同属性上的一系列连接点。
我们在Test8
中做一个简单的测试。Test8
包结构与上面的Test7
一样。
Service
类与上例中一样,这里不再赘述。测试类Main
中,我们将对属性的访问修改为对属性的修改,如下:
package Test8;
public class Main
public static void main(String[] args)
Service service = new Service();
Service.name = "Gavin0 John0";
service.setFirstname("Gavin0");
service.setLastname("John0");
首先我们直接通过属性名字修改name
属性。接着调用firstname
和lastname
的setter
方法。
接着添加切面FieldAspect
,如下:
package Test8;
public aspect FieldAspect
pointcut setNamePointcut(): set(String Service.*name);
before(): setNamePointcut()
System.out.println();
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
切入点setNamePointcut
使用set(Singature)
和通配符定义了对Service
类中以name
结尾的属性的修改切入点。
运行程序,结果如下:
可以看到,切面捕获了对三个属性的修改,但是奇怪的是每个属性都修改了两遍,这是为什么呢?其实不难理解,在Service
类中,我们对这三个属性的第一次赋值,也算是一次修改,这也被切面捕获了。
3.在修改属性时获取赋给它的值
假如我们想在通知中获取,修改属性的时候赋给属性的值,该怎么做呢?这可以结合我们前面用过的args
原生切入点,获取给其传递的参数即可。
如上例,我们将切面修改如下:
package Test8;
public aspect FieldAspect
pointcut setNamePointcut(String newValue): set(String Service.*name) && args(newValue);
before(String newValue): setNamePointcut(newValue)
System.out.println();
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
System.out.println("赋给属性的值是:" + newValue);
此时的运行结果是:
以上是关于AspectJ——切入点语法之捕获属性上的连接点的主要内容,如果未能解决你的问题,请参考以下文章