2014-10-29 44 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