切面aspect由advice和pointcut组成,早特定切点pointcut进行通知。
同样,aspect本身也可以被通知。
定义:adviceexecution()
Picks out all advice execution join points.
形式:adviceexecution()
作用:for example, to filter out any join point in the control flow of advice from a particular aspect.
捕获何时执行通知
即aspect被通知了
demo
package aspectj;
public class MyClass {
public void b() {
System.out.println("call b");
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.b();
}
}
package aspectj;
public aspect HelloWorld {
pointcut callPointcut():call(void aspectj.MyClass.b());
before(): callPointcut() && !within(HelloWorld)
{
System.out.println("hello");
}
}
//处理aspect的通知
package aspectj;
public aspect AdviceExecute {
pointcut advicePoint():adviceexecution();
//不包含当前的aspect,否则递归产生stackoverflow
before(): advicePoint() && !within(AdviceExecute)
{
System.out.println("aspect advice logic");
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(thisJoinPoint.getSignature());
}
}
输出
aspect advice logic
HelloWorld.aj:6
void aspectj.HelloWorld.before()
hello
call b
注意避免stackoverflow
参考上图即可理解
排除作为通知执行结果的连接点
即通知块内调用的代码能继续触发其他或当前通知块,希望忽略掉,完成filter操作
结合 cflow使用
定义:cflow(Pointcut)
Picks out each join point in the control flow of any join point P picked out by Pointcut, including P itself.
形式:cflow(Pointcut)
这个和 捕获何时执行通知 并没什么关系,不需要知道何时执行通知,只是执行通知时进行过滤
所以不需要上面的AdviceExecute
demo
package aspectj;
public aspect HelloWorld {
pointcut callPointcut():call(void aspectj.MyClass.b());
before(): callPointcut()
{
System.out.println("hello");
MyClass myClass = new MyClass();
//在通知块内的代码能继续触发当前通知块
myClass.b();
System.out.println("HelloWorld end ----");
}
}
发现stackoverflow了,因为通知块内调用的代码能继续通知当前aspect,造成递归。
为了filter掉当前aspect的通知,利用cflow(其实用within也可以)
改成下面这种形式
package aspectj;
public aspect HelloWorld {
pointcut callPointcut():call(void aspectj.MyClass.b());
/*
下面两种都能进行过滤,区别在于!within这个限定了过滤当前aspect
而cflow结合adviceexecution过滤掉了所有通知内控制流造成的通知
*/
// before(): callPointcut() && !within(HelloWorld)
before(): callPointcut() && !cflow(adviceexecution())
{
System.out.println("hello");
MyClass myClass = new MyClass();
myClass.b();
System.out.println("HelloWorld end ----");
}
}
在发出通知时展示原始连接点
按照demo来跑并跑步起来,不知道原因是什么,又不方便debug,也不说错在哪
package aspectj;
import org.aspectj.lang.JoinPoint;
public aspect AdviceExecute {
pointcut advicePoint1(JoinPoint joinPoint) : adviceexecution() && args(joinPoint) && !within(AdviceExecute);
before(JoinPoint joinPoint): advicePoint1(joinPoint)
{
System.out.println("aspect advice logic1");
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(thisJoinPoint.getSignature());
System.out.println(joinPoint.getSignature());
System.out.println(joinPoint.getSourceLocation());
}
}
个人理解
捕获何时执行通知 相当于 aspect再做一层通知,可以用来看触发了多少次,多少种aspect,统计用
排除作为通知执行结果的连接点 相当于 filter,即aspect通知时,可以过滤掉某些pointcut的通知
问题
在发出通知时展示原始连接点这个demo并没有跑起来
refer
https://eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html
《aspectj cookbook》