我对AspectJ中的 cflow 或 cflowbelow 有疑问。
cflow的(切入点)
选出控制流程中的所有连接点 切入点切出的点,包括切入点的加入点 指出自己。
cflowbelow(Pointcut)
选出控制流程中的所有连接点 在切入点选择的连接点下面。
对于两者,我只能找到定义和那个:
使用 cflow 或 cflowbelow 定义切入点时,我们需要确保 切入点不会捕获从中进行的调用 相同方面,否则它将调用递归方法调用和我们 会得到 StackOverflowError 。
这是因为 cflow()也会发生 从方面本身捕获方法调用并尝试应用 给它的建议。使用within()构造可以避免这种情况。 in()将类型(类或接口)名称作为参数和 捕获在该类型中定义的所有连接点。
但是没有解释实际上cflow()或cflowbelow()在没有 之内或与&&同时使用时会导致无限递归。表达式如:
pointcut aPointcut(): execution(void Test.foo()) && !cflowbelow(execution(void Test.foo()));
哪个匹配,例如Test.foo()
的第一次执行,如果在Test.foo()
内Test.foo()
进行另一次调用,或者调用foo()
类扩展Test
方法,则忽略任何冒泡是制造的。
我的问题是:为什么cflow在使用时实际上会导致无限递归,例如不在内?如何进行cflow编织以便导致这种递归?
答案 0 :(得分:2)
一个简单的例子:
驱动程序应用程序:
package de.scrum_master.app;
public class Application {
public static void sayHelloTo(String name) {
System.out.println("Hello " + name + "!");
}
public static void main(String[] args) {
sayHelloTo("world");
}
}
<强>方面:强>
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
public aspect CflowRecursionDemo {
// Attention, StackOverflowError!
/*
before() : cflow(execution(* Application.sayHelloTo(..))) {
System.out.println(thisJoinPoint);
}
*/
before() : !within(CflowRecursionDemo) && cflow(execution(* Application.sayHelloTo(..))) {
System.out.println(thisJoinPoint);
}
}
注释掉的建议导致StackOverflowError
,而活跃的建议则不会。
控制台输出:
execution(void de.scrum_master.app.Application.sayHelloTo(String))
get(PrintStream java.lang.System.out)
call(java.lang.StringBuilder(String))
call(StringBuilder java.lang.StringBuilder.append(String))
call(StringBuilder java.lang.StringBuilder.append(String))
call(String java.lang.StringBuilder.toString())
call(void java.io.PrintStream.println(String))
Hello world!
说明:正如您所看到的,活动建议的控制流中有许多连接点。其中每一个都会再次触发主动建议,因为它们中的每个都再次与切入点cflow(execution(* Application.sayHelloTo(..)))
匹配。建议是一种像任何其他方法一样的方法,但它恰好在一个方面内。无论如何,它在其自己的切入点的控制流程中再次触发建议,该建议又在其自己的切入点的控制流程中等等。无限递归!