0

我想使用 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中所述, 但我不明白如何编写切入点所以一个无限循环不会被创建。

帮助

4

1 回答 1

2

您的代码中有几个问题:

  • !codeWithinAspect需要括号:!codeWithinAspect()
  • adviceWithInfiniteLoop()以这种方式组合execution()call()切入点:execution(foo) && !call(bar). 因为调用连接点永远不可能是执行连接点,所以条件的第二部分始终为真且无效。因此,它并没有避免无限循环。
  • 您不仅要排除切面内的连接点,还要排除切面方法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() {}
于 2014-10-30T09:01:05.947 回答