AOP - 错误:org.aspectj.runtime.internal.AroundClosure

时间:2016-02-18 16:02:01

标签: java stack-overflow aop aspectj aspect

我正在尝试使用面向方面编程来执行简单的Fibonacci函数并跟踪对any的所有调用 方法除了Java中的方法,还显示嵌套 他们的水平。

Java代码:

package tracing;

public class Test {

    static int fib(int n) {
        if (n<=1)
            return n;
        else
            return fib(n-1) + fib(n-2);
    }

    static void report(int n,int r) {
        System.out.println("fib("+n+")="+r);
    }

    public static void main(String[] a) {
        report(4,fib(4));
    }
}

AspectJ代码:

package tracing;

public aspect Trace {
    String prefix = "";

    Object around(): call(* *(..)) && !within(java..*) && !within(FigureEditor..*) {
        System.out.println(prefix+thisJoinPoint.getSignature());
        prefix = ">" + prefix;
        Object result = proceed();
        prefix = prefix.substring(1);
        return result;
    }
}

注意:&& !within(FigureEditor..*)仅用于避免不同包的类中的函数。

控制台输出 - 错误:

Exception in thread "main" java.lang.StackOverflowError     at
org.aspectj.runtime.internal.AroundClosure.<init>(AroundClosure.java:34)
    at tracing.Trace$AjcClosure1.<init>(Trace.aj:1)     at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)

更新:我想要的输出类似于以下内容:

void Test.main(String [])
>void Test.report(int, int)<br>
>>int Test.fib(int)<br>
>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>>>>>int Test.fib(int)<br>
>>>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>> void Test.write(String) fib(4)=3

2 个答案:

答案 0 :(得分:2)

我不确定您是否正在使用Eclipse或其他IDE来开发AspectJ代码,但如果这样做,您可能会注意到在{{1}的方法体中IDE显示了AspectJ标记。建议本身,这意味着他们自己(你的around()建议中的方法调用)被你的方面编织,如下图所示:

AspectJ markers shown in the advice itself

这意味着,为了避免在around()建议中发生无限递归,从内部重复调用建议,您需要排除建议的控制流以获得建议。您可以通过包含以下切入点表达式<{1}}来轻松排除任何建议的控制流中的所有代码,因此您的方面代码看起来像这样(重新格式化了一点):

around()

来自AspectJ documentation on pointcut expressions

  

!cflow(adviceexecution()):选出Pointcut选取的任何连接点P的控制流中的每个连接点,包括P本身。

     

public aspect Trace { String prefix = ""; Object around(): call(* *(..)) && !within(java..*) && !within(FigureEditor..*) && !cflow(adviceexecution()) { System.out.println(prefix+thisJoinPoint.getSignature()); prefix = ">" + prefix; Object result = proceed(); prefix = prefix.substring(1); return result; } } :挑出所有建议执行连接点。

编辑:添加Aspect代码以反映更新的问题

您对原始问题的更新可以明确您的意图。我已更新方面代码以反映这些更改。结果方面如下所示:

cflow(Pointcut)

我替换了所有通知执行代码的控制流的排除,仅排除adviceexecution()方面,并包括运行时测试以排除public aspect Trace { String prefix = ""; Object around(): call(* *(..)) && !within(java..*) && !if(thisJoinPoint.getTarget()!=null && thisJoinPoint.getTarget().getClass().getName().startsWith("java")) && !within(FigureEditor..*) && !within(Trace) { System.out.println(prefix+thisJoinPoint.getSignature()); prefix = ">" + prefix; Object result = proceed(); prefix = prefix.substring(1); return result; } } 包中对代码的所有调用。 / p>

答案 1 :(得分:2)

虽然Nándor的答案是正确的,但它也很昂贵,因为在运行时期间会评估cflow()cflowbelow()等控制流切入点。我建议你只使用!within(Trace),它可以在编译期间进行评估并且更快。

您还希望使用更简单的方法来排除对Java类的调用,而不涉及任何反射:!call(* java..*(..))

package tracing;

public aspect Trace {
    String prefix = "";

    Object around() :
        !within(Trace) &&
        call(* *(..)) &&
        !call(* java..*(..)) &&
        !within(FigureEditor..*)
    {
        System.out.println(prefix + thisJoinPoint.getSignature());
        prefix = ">" + prefix;
        Object result = proceed();
        prefix = prefix.substring(1);
        return result;
    }
}

这产生了所需的输出:

int tracing.Test.fib(int)
>int tracing.Test.fib(int)
>>int tracing.Test.fib(int)
>>>int tracing.Test.fib(int)
>>>int tracing.Test.fib(int)
>>int tracing.Test.fib(int)
>int tracing.Test.fib(int)
>>int tracing.Test.fib(int)
>>int tracing.Test.fib(int)
void tracing.Test.report(int, int)
fib(4)=3