【问题标题】:AOP - Error: java.lang.StackOverflowError at org.aspectj.runtime.internal.AroundClosureAOP - 错误:org.aspectj.runtime.internal.AroundClosure 处的 java.lang.StackOverflowError
【发布时间】:2023-03-28 04:32:01
【问题描述】:

我正在尝试使用面向方面的编程来执行一个简单的斐波那契函数并跟踪对任何 除了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;
    }
}

注意:&amp;&amp; !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

【问题讨论】:

  • 我已经修复了您的格式问题。代码格式的语法是缩进 4 个空格,您还应该将其用于控制​​台日志,而不是引用语法 ">"。

标签: java stack-overflow aop aspectj aspect


【解决方案1】:

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

这意味着,为了避免在您的around() 建议中出现无限递归,即从内部重复调用建议,您需要排除建议的控制流。您可以排除任何建议的控制流中的所有代码,只需包含以下切入点表达式:!cflow(adviceexecution()),因此您的方面代码将如下所示(重新格式化):

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;
    }
}

来自AspectJ documentation on pointcut expressions

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

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;
    }
}

我将所有建议执行代码的控制流排除替换为仅排除 Trace 方面,并包含一个运行时测试以排除对 java 包中代码的所有调用。

【讨论】:

  • 我已经更新了我的问题,看看我想要什么输出......现在执行工作正常,没有问题......但我得到的输出是这样的:int tracing.Test.fib(int) void tracing.Test.report(int, int) fib(4)=3
  • 我在回答中添加了详细信息,以反映您问题的变化。
  • @NándorElődFekete:你觉得我的回答怎么样?我认为它比您的要简单得多,并且不涉及运行时检查或反射。
  • @kriegaex 你完全正确。我的解决方案不是最理想的。你的答案是完美的。
【解决方案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

【讨论】:

  • 一切正常。我会记住有关cflow()cflowbelow() 的信息。
猜你喜欢
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 1970-01-01
  • 2019-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多