我想使用AspectJ记录我在代码中进行的所有方法调用,除了记录器中的方法之外。
@Aspect
public class Logger
{
// Point Cuts
//-----------
@Pointcut("execution(* org.myDomain.*..*.*(..))")
public void selectAll(){}
@Pointcut("within(Logger) && call(* *(..))")
public void codeWithinAspect(){}
// Advices
//-----------
@Before("selectAll()")
public void adviceThatWorksFine(JoinPoint joinPoint)
{
System.out.print(joinPoint.getSignature().toString());
//Utils.printToConsole(joinPoint.getSignature().toString());
}
@Before("selectAll() && !codeWithinAspect")
public void adviceWithInfiniteLoop(JoinPoint joinPoint)
{
//System.out.print(joinPoint.getSignature().toString());
Utils.printToConsole(joinPoint.getSignature().toString());
}
}
该类中的第一个建议工作正常(它将每个方法调用写入控制台),第二个建议在调用org.myDomain.utils.Utils.printToConsole()方法时导致无限循环,这是通过调用建议的建议。
我发现这是链接中描述的常见问题 http://www.eclipse.org/aspectj/doc/released/faq.php#q:infiniterecursion 但我无法理解如何编写切入点,因此无法创建无限循环。
帮助
答案 0 :(得分:2)
您的代码中存在几个问题:
!codeWithinAspect
需要括号:!codeWithinAspect()
adviceWithInfiniteLoop()
以这种方式结合了execution()
和call()
切入点:execution(foo) && !call(bar)
。因为调用连接点永远不能是执行连接点,所以条件的第二部分始终为true且无效。因此,它无法避免无限循环。Logger
中排除连接点,还要排除该方面方法的控制流(cflow()
)内的连接点,即由它们直接或间接调用的内容。解决方案如下:
日志输出的实用程序类:
package org.myDomain.app;
public class Utils {
public static void printToConsole(Object object) {
System.out.println(object);
}
}
驱动程序应用程序:
package org.myDomain.app;
public class Application {
public static void sayHelloTo(String counterpart) {
Utils.printToConsole("Hello " + counterpart + "!");
}
public static void main(String[] args) {
sayHelloTo("world");
}
}
记录器方面:
package org.myDomain.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.myDomain.app.Utils;
@Aspect
public class Logger {
@Pointcut("execution(* org.myDomain..*(..))")
public void selectAll() {}
@Pointcut("cflow(within(Logger))")
public void codeWithinAspect() {}
@Before("selectAll() && !codeWithinAspect()")
public void advice(JoinPoint joinPoint) {
Utils.printToConsole(joinPoint);
}
}
控制台输出:
execution(void org.myDomain.app.Application.main(String[]))
execution(void org.myDomain.app.Application.sayHelloTo(String))
execution(void org.myDomain.app.Utils.printToConsole(Object))
Hello world!
享受!
更新:如果要排除所有建议执行控制流,您也可以使用此切入点:
@Pointcut("cflow(adviceexecution())")
public void codeWithinAspect() {}