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());  
    }
}

クラスの最初のアドバイスは問題なく機能します (すべてのメソッド呼び出しをコンソールに書き込みます)。

リンク http://www.eclipse.org/aspectj/doc/released/faq.php#q:infiniterecursionで説明されているように、これは一般的な問題であることがわかりましたが 、ポイントカットの記述方法が理解できなかったため、無限ループになりました作成されません。

助けてください

4

1 に答える 1

2

コードにはいくつかの問題があります。

  • !codeWithinAspect括弧が必要です:!codeWithinAspect()
  • adviceWithInfiniteLoop()この方法で結合execution()し、call()ポイントカットします: execution(foo) && !call(bar). 呼び出しジョインポイントが実行ジョインポイントになることは決してないため、条件の 2 番目の部分は常に真であり、効果はありません。したがって、無限ループは避けられません。
  • 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 に答える