AspectJ - 当cflow未与&&组合时,为什么cflow会导致无限递归(aspectJ交集)?

时间:2015-03-31 07:58:07

标签: recursion stack-overflow aop aspectj

我对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编织以便导致这种递归?

1 个答案:

答案 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(..)))匹配。建议是一种像任何其他方法一样的方法,但它恰好在一个方面内。无论如何,它在其自己的切入点的控制流程中再次触发建议,该建议又在其自己的切入点的控制流程中等等。无限递归!