这里介绍
advice如何和程序的类交互
不同类型的advice
advice的优先级
访问类成员
可以通过privileged修饰aspect让切面能够访问类私有成员
demo
package aspectj;
public class MyClass {
private int b;
public int getB() {
return b;
}
public void doSth(){};
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.doSth();
}
}
package aspectj;
public privileged aspect HelloWorld {
pointcut callMethod(MyClass myClass):execution (* MyClass.doSth()) && this(myClass);
before(MyClass myClass) : callMethod(myClass) && !within(HelloWorld){
System.out.println(thisJoinPoint.getSignature());
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(thisJoinPoint.getKind());
System.out.println(thisJoinPoint.getThis());
myClass.b = 3;
System.out.println(myClass.getB());
}
}
输出
void aspectj.MyClass.doSth()
MyClass.java:8
method-execution
aspectj.MyClass@12edcd21
3
分析:
通过privileged 访问了类的私有成员
这里pointcut如果从execution 改成 call,那么并不会有输出
因为call是从MyClass的static方法调用的,并没有"this"这个对象
访问连接点环境
thisJoinPoint展示this连接点环境,包含静态和动态环境信息
静态环境是编译和织入时决定的信息
动态环境是运行时填充的
thisJoinPointStaticPart展示当前的静态环境,即不包含运行时填充的信息
注意
It is always the case that
thisJoinPointStaticPart == thisJoinPoint.getStaticPart()
thisJoinPoint.getKind() == thisJoinPointStaticPart.getKind()
thisJoinPoint.getSignature() == thisJoinPointStaticPart.getSignature()
thisJoinPoint.getSourceLocation() == thisJoinPointStaticPart.getSourceLocation()
通知的执行顺序
分为下面几种
before( Formals )
after( Formals ) returning [ ( Formal ) ]
after( Formals ) throwing [ ( Formal ) ]
after( Formals )
Type around( Formals )
依次介绍如下
在连接点之前执行通知
即before(),不赘述
在连接点周围执行通知
用around()通知
包围一个连接点的通知,如方法调用。
这是最 强大的通知。Around通知在方法调用前后完成自定义的行为。它们负责选择继续执行连接点或通过 返回它们自己的返回值或抛出异常来短路执行。
必须具有指定返回值
和前置before和后置after的区别
1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法(是否调用proceed)
而前置和后置通知 是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。
2) 环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用
demo
package aspectj;
public class MyClass {
public int doSth(String t){
return 1;
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
int x = myClass.doSth("this string");
System.out.println("return value is " + x);
}
}
package aspectj;
public aspect HelloWorld {
pointcut callpointcut(String x):call(* MyClass.doSth(*)) && args(x);
//必须定义返回值
int around(String x) : callpointcut(x) && !within(HelloWorld){
System.out.println("param value is '" + x + "'");
System.out.println(thisJoinPoint.getSignature());
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(thisJoinPoint.getKind());
System.out.println("before");
//调用原有目标方法
int t = proceed(x);
System.out.println("after");
//这里修改了返回值
return t * 10;
}
}
输出
param value is 'this string'
int aspectj.MyClass.doSth(String)
MyClass.java:9
method-call
before
after
return value is 10
分析:
这里可以完成一些前置工作如参数验证等等
可以决定是否走入原有逻辑(不想的话则不调用proceed即可)
还可以修改返回值(后置after是不能修改返回值的)
在连接点之后无条件执行
after()即可,不赘述
仅在连接点正常返回后才执行通知
after( Formals ) returning [ ( Formal ) ]
和after也差不多
仅当连接点引发异常才执行通知
after( Formals ) throwing [ ( Formal ) ]
demo
package aspectj;
public class MyClass {
public int doSth(String t) throws Exception{
throw new RuntimeException();
}
public static void main(String[] args) throws Exception{
MyClass myClass = new MyClass();
try {
int x = myClass.doSth("this string");
} catch (Exception e) {
}
}
}
package aspectj;
public aspect HelloWorld {
pointcut callpointcut(String x):call(* MyClass.doSth(*)) && args(x);
after (String x) throwing: callpointcut(x) && !within(HelloWorld){
System.out.println("after value is '" + x + "'");
System.out.println(thisJoinPoint.getSignature());
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(thisJoinPoint.getKind());
}
}
after value is 'this string'
int aspectj.MyClass.doSth(String)
MyClass.java:10
method-call
控制通知优先级
declare precedence即可
具体的详细规则参照
https://eclipse.org/aspectj/doc/released/progguide/semantics-advice.html#advice-modifiers里面
截图!!!
通知方面
即通过pointcut完成特定aspect相关的通知
比如上面代码中的
!within(HelloWorld)
这个就是exclude掉HelloWorld内的pointcut,作为通知
思考
静态环境和动态环境的区别
around通知能够决定原有目标方法是否调用(proceed),可以修改返回值,因此是将原有逻辑"包"起来了
refer
https://eclipse.org/aspectj/doc/released/progguide/semantics-aspects.html
http://www.eclipse.org/aspectj/doc/next/progguide/language-thisJoinPoint.html
https://eclipse.org/aspectj/doc/released/progguide/semantics-advice.html#advice-modifiers
http://www.cnblogs.com/gmq-sh/p/6018587.html