AOP - Error: java.lang.StackOverflowError at org.aspectj.runtime.internal.AroundClosure
AOP - Error: java.lang.StackOverflowError at org.aspectj.runtime.internal.AroundClosure
我正在尝试使用面向方面的编程来执行一个简单的斐波那契函数并跟踪对任何
除了 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..*)
只是用来避免其他包的class中的函数。
控制台输出 - 错误:
Exception in thread "main" java.lang.WhosebugError 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$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$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
我不确定您是使用 Eclipse 还是其他一些 IDE 来开发您的 AspectJ 代码,但是如果您这样做,您可能会注意到 [=41= 显示了 AspectJ 标记] 在您的 around()
建议本身的方法主体中,这意味着它们本身(您的 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)
: Picks out each join point in the control flow of any join point P picked out by Pointcut, including P itself.
adviceexecution()
: Picks out all advice execution join points.
编辑:添加方面代码以反映更新后的问题
您对原始问题的更新阐明了您的意图。我已经更新了方面代码以反映这些变化。结果方面将如下所示:
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
包中代码的所有调用.
虽然 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
我正在尝试使用面向方面的编程来执行一个简单的斐波那契函数并跟踪对任何 除了 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..*)
只是用来避免其他包的class中的函数。
控制台输出 - 错误:
Exception in thread "main" java.lang.WhosebugError 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$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$ef88057b(Trace.aj:7) at
tracing.Trace.ajc$around$tracing_Trace$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
我不确定您是使用 Eclipse 还是其他一些 IDE 来开发您的 AspectJ 代码,但是如果您这样做,您可能会注意到 [=41= 显示了 AspectJ 标记] 在您的 around()
建议本身的方法主体中,这意味着它们本身(您的 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)
: Picks out each join point in the control flow of any join point P picked out by Pointcut, including P itself.
adviceexecution()
: Picks out all advice execution join points.
编辑:添加方面代码以反映更新后的问题
您对原始问题的更新阐明了您的意图。我已经更新了方面代码以反映这些变化。结果方面将如下所示:
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
包中代码的所有调用.
虽然 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