0

スタンドアロン アプリケーションで AspectJ を使用しようとしていますが、機能していないようです。

ここに私が作成したクラスがあります-

package oata.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AspectJTest {


    @Around("execution(* *..*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("around fired");
        jp.proceed();
    }
}
package oata;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface AspectTest {
}
package oata;

import oata.AspectTest;

public class TestAspect {
    public void doItWithout(int i) {
        double s = Math.acos(i);
    }

    @AspectTest
    public void doItAnnotated(int i) {
        double s = Math.acos(i);
    }

    public void doItAspect(int i) {
        double s = Math.acos(i);

    }
}
package oata;

import java.util.Date;

public class Test {
    public Test() {
    }

    public static void main(String arg[]) {
        // performance testing
        // invoke method without aspect
        long t1 = new Date().getTime();
        for (int i = 0; i < 1; i++) {
            new TestAspect().doItWithout(i);
        }
        System.out.println("Invoke without aspect:"
                + (new Date().getTime() - t1));
        // invoke method with annotated aspect
        t1 = new Date().getTime();
        for (int i = 0; i < 1; i++) {
            new TestAspect().doItAnnotated(i);
        }
        System.out.println("Invoke annotated aspect method:"
                + (new Date().getTime() - t1));
        // invoke method with aspect but not annotated
        t1 = new Date().getTime();
        for (int i = 0; i < 1; i++) {
            new TestAspect().doItAspect(i);
        }
        System.out.println("Invoke aspect method:"
                + (new Date().getTime() - t1));
    }
}

また、src/META_INF フォルダーの下に aop.xml ファイルを作成しました

<aspectj>
    <aspects>
        <aspect name="oata.aspect.AspectJTest" />
    </aspects>
    <weaver>
        <include within="oata.*" />
    </weaver>
</aspectj>

次に、コマンド ラインから以下のコマンドを使用して Test.java を実行しようとすると、アドバイスの System.out.println が出力されません。

\TestAspectJ\bin>java -javaagent:D:\Project\workspaces\RCS_3.2.1\TestAspectJ\src\aspectjweaver-1.6.10.jar oata.Test

誰でも私が間違っていることを教えてください。

ありがとうAA

4

2 に答える 2

2

アンディの言うことはすべて正しい。あなたは Java だけでなく AspectJ の初心者でもあるように思われるため、使い始めるのに役立つように、サンプル コードを少しリファクタリングしました。途中で気づいたこと:

  • 非常に古い AspectJ バージョン 1.6.10 を使用しています。これは 2010 年のものであり、最新の 1.6 バージョン (1.6.12) でさえありません。現在の AspectJ バージョン 1.8.6 を使用するのはどうですか?
  • 私はきれいなコードの男ですが、クラス名がサンプル コードで示したいことをかなり難読化していることに気付きました。だから私はそれらの名前を変更しました:
    • TestApplication
    • TestAspectHelper
    • AspectTestMyAnnotation
    • AspectJTestMethodInterceptor
  • また、次の問題を示すためHelper以外の何かを返すように、メソッドの戻り値の型を変更しました。void
  • アドバイス@Aroundの戻り値の型はvoidです。この方法では、ポイントカットが非 void メソッドにヒットした場合は機能しません。より一般的な方法でこれを行う方法を示すために、戻り値の型とObject結果を返すコードを変更しproceed()ました。
  • あなたの@Aroundアドバイスは常に同じメッセージを記録します。proceed()コンソールログで何が起こっているかを確認できるように、実際のジョインポイント情報 (呼び出しの前後) をログに記録するように更新しました。
  • アンディが言ったように、注釈付きのメソッドをポイントカットと一致させるために注釈を使用することを計画しているのは明らかです。したがって、保持範囲を に変更しましたRUNTIME
  • ポイントカットは、Application.mainおよびを含むすべてのメソッドの実行を対象としてHelper.doItWithoutいます。@MyAnnotationポイントカットを変更して、メソッド名に「Aspect」という部分文字列を含むか、含むメソッドのみをターゲットにしました。
  • メソッドの実行時間をプロファイリングし、アスペクトの対象外のメソッドに適用されたアスペクトとメソッドを比較したいようです。多くのDateインスタンスを作成して (ミリ秒を返す) を呼び出す代わりに、 (ナノ秒を返すnew Date().getTime()) を使用できます。System.nanoTime()
  • プロファイリングでは、オブジェクトの作成時間ではなく、メソッドの実行時間を測定する必要があります。したがって、メソッドHelper全体で再利用されるインスタンスを1 つだけ作成するようにコードを変更しました。main
  • クラスはApplicationJVM によって自動的に生成されるため、空のデフォルト コンストラクターは必要ありません。
  • 意味のあるプロファイリング結果を得るには、より多くの繰り返し (100 万回など) を使用する必要があります。LOOP_COUNT3 つのループすべてでこれを単純化するために、という名前の定数を導入しました。
  • 注意!メソッドの実行時間を測定したい場合は、コンソールに何かを書き込むのにかかる時間も測定することになるため、アスペクトに何も出力しないでください。したがって、アスペクトの印刷ステートメントをコメントアウトしました。何が起こっているかを確認するために、より少ない回数の繰り返しでアクティブにすることができます。

リファクタリングされたコード:

package oata;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
package oata;

import oata.MyAnnotation;

public class Helper {
    public double doItWithout(int i) {
        return Math.acos(i);
    }

    @MyAnnotation
    public double doItAnnotated(int i) {
        return Math.acos(i);
    }

    public double doItAspect(int i) {
        return Math.acos(i);
    }
}
package oata;

public class Application {
    private static final int LOOP_COUNT = 100000000;

    public static void main(String arg[]) {
        Helper helper = new Helper();
        System.out.printf(
            "Profiling statistics for %,d repetitions%n%n",
            LOOP_COUNT
        );

        long startTime = System.nanoTime();
        for (int i = 0; i < LOOP_COUNT; i++)
            helper.doItWithout(i);
        System.out.printf(
            "Method not targeted by aspect:%n    %,15d ns%n",
            System.nanoTime() - startTime
        );

        startTime = System.nanoTime();
        for (int i = 0; i < LOOP_COUNT; i++)
            helper.doItAnnotated(i);
        System.out.printf(
            "Method targeted by aspect because it is annotated:%n    %,15d ns%n",
            System.nanoTime() - startTime
        );

        startTime = System.nanoTime();
        for (int i = 0; i < LOOP_COUNT; i++)
            helper.doItAspect(i);
        System.out.printf(
            "Method targeted by aspect because of its name:%n    %,15d ns%n",
            System.nanoTime() - startTime
        );
    }
}
package oata.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MethodInterceptor {
    @Around("execution(@oata.MyAnnotation * *(..)) || execution(* *Aspect*(..))")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
//      System.out.println("BEFORE " + jp);
        Object result = jp.proceed();
//      System.out.println("AFTER  " + jp);
        return result;
    }
}

アスペクト ログ ステートメントを有効にした 1 回の繰り返しのコンソール ログの例:

Profiling statistics for 1 repetitions

Method not targeted by aspect:
            153.893 ns
BEFORE execution(double oata.Helper.doItAnnotated(int))
AFTER  execution(double oata.Helper.doItAnnotated(int))
Method targeted by aspect because it is annotated:
          3.102.128 ns
BEFORE execution(double oata.Helper.doItAspect(int))
AFTER  execution(double oata.Helper.doItAspect(int))
Method targeted by aspect because of its name:
             55.295 ns

ここでわかるように、メソッドごとに 1 つの呼び出しだけでは、結果はあまり決定的ではありません。

アスペクト ログ ステートメントを無効にして 100,000,000 (1 億) 回繰り返した場合のコンソール ログの例:

Profiling statistics for 100.000.000 repetitions

Method not targeted by aspect:
        843.407.034 ns
Method targeted by aspect because it is annotated:
      1.219.571.173 ns
Method targeted by aspect because of its name:
      1.175.436.574 ns

結果はより決定的になりました: どのアスペクトにも対象とされていないメソッドは、実行時間が 1.2 秒とほぼ等しい次の 2 つのメソッドよりも速く実行されます。 CTW の場合) または製織時間 (LTW の場合)。

于 2015-08-30T09:35:48.750 に答える