2014-10-29 45 views
0

我想记录我在代码中使用AspectJ在记录器中生成的所有方法调用。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 所述,但我无法理解如何编写切入点,因此无法创建无限循环。

plaes帮助

回答

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() {} 
+0

感谢,它的工作原理,甚至更好地与adviceexecution – Tal 2014-10-30 14:09:42