我正在尝试使用面向方面编程来执行简单的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
答案 0 :(得分:2)
我不确定您是否正在使用Eclipse或其他IDE来开发AspectJ代码,但如果这样做,您可能会注意到在{{1}的方法体中IDE显示了AspectJ标记。建议本身,这意味着他们自己(你的around()
建议中的方法调用)被你的方面编织,如下图所示:
这意味着,为了避免在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