AspectJの紹介

1前書き

この記事はAspectJの 簡単で実用的な紹介です。

最初に、アスペクト指向プログラミングを有効にする方法を示してから、コンパイル時、ポストコンパイル、およびロード時のウィービングの違いに焦点を当てます。

まずアスペクト指向プログラミング(AOP)とAspectJの基本の簡単な紹介から始めましょう。

2概要

AOPは分野横断的な関心事の分離を可能にすることによってモジュール性を高めることを目的とするプログラミングパラダイムです。これは、コード自体を変更せずに既存のコードに追加の動作を追加することによって行われます。代わりに、どのコードを変更するかを個別に宣言します。

AspectJ は、Javaプログラミング言語の拡張機能を使用して、懸念と横断的な懸念の織り込みの両方を実装しています。

3 Mavenの依存関係

AspectJはその用途に応じて異なるライブラリを提供しています。 Maven Centralのリポジトリにあるhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.aspectj%22[org.aspectj]グループの下にMavenの依存関係があります。

この記事では、アスペクトを作成するために必要な依存関係と、コンパイル時、ポストコンパイル時、およびロード時のWeaversを使用したWeaverに焦点を当てます。

3.1. AspectJランタイム

AspectJプログラムを実行するときは、クラスパスにAspectJランタイムライブラリ__aspectjrt.jarと共にクラスとアスペクトを含める必要があります。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.9</version>
</dependency>

この依存関係はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.aspectj%22%20AND%20a%3A%22aspectjrt%22[Maven Central]で入手可能です。

3.2. AspectJWeaver

AspectJランタイム依存性の他に、ロード時にJavaクラスにアドバイスを導入するために aspectjweaver.jar を含める必要があります。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>

依存関係はhttps://search.maven.org/classic/#artifactdetails%7Corg.aspectj%7Caspectjweaver%7C1.8.9%7Cjar[Maven Central]でも入手できます。

4アスペクト作成

AspectJはAOPの実装を提供し、3つのコアコンセプトを持っています。

  • ジョインポイント

  • ポイントカット

  • 助言

ユーザーアカウントの残高を検証するための簡単なプログラムを作成して、これらの概念を実証します。

まず、所定の残高と撤回する方法で Account クラスを作成しましょう。

public class Account {
    int balance = 20;

    public boolean withdraw(int amount) {
        if (balance < amount) {
            return false;
        }
        balance = balance - amount;
        return true;
    }
}

アカウント情報を記録し、アカウントの残高を検証するために AccountAspect.aj ファイルを作成します(AspectJファイルの末尾には " .aj "という拡張子が付いています)。

public aspect AccountAspect {
    final int MIN__BALANCE = 10;

    pointcut callWithDraw(int amount, Account acc) :
     call(boolean Account.withdraw(int)) && args(amount) && target(acc);

    before(int amount, Account acc) : callWithDraw(amount, acc) {
    }

    boolean around(int amount, Account acc) :
      callWithDraw(amount, acc) {
        if (acc.balance < amount) {
            return false;
        }
        return proceed(amount, acc);
    }

    after(int amount, Account balance) : callWithDraw(amount, balance) {
    }
}

ご覧のとおり、 pointcut をwithdrawメソッドに追加し、定義された pointcut を参照する3つの advises を作成しました。

以下を理解するために、以下の定義を紹介します。

  • アスペクト :複数にまたがる懸念のモジュール化

オブジェクト各側面は、特定の分野横断的機能に焦点を当てています。 Join point ** :スクリプトの実行中のポイント。

メソッドまたはプロパティアクセスの実行 アドバイス** :特定の参加ポイントでアスペクトによって取られたアクション

  • Pointcut :結合点と一致する正規表現。アドバイス

ポイントカット式に関連付けられており、ポイントカットに一致する任意のジョインポイントで実行されます。

これらの概念とその具体的な意味についての詳細は、https://eclipse.org/aspectj/doc/next/progguide/semantics-pointcuts.html[link]を参照してください。

次に、アスペクトをコードに織り込む必要があります。以下のセクションでは、コンパイル時ウィービング、ポストコンパイルウィービング、AspectJでのロード時ウィービングの3種類のウィービングについて説明します。

5コンパイル時の製織

最も簡単な製織方法はコンパイル時の製織です。アスペクトのソースコードとアスペクトを使用しているコードの両方がある場合、AspectJコンパイラはソースからコンパイルして出力として編まれたクラスファイルを生成します。その後、コードを実行すると、ウィービングプロセスの出力クラスが通常のJavaクラスとしてJVMにロードされます。

バンドルされたAspectJコンパイラが含まれているので、https://eclipse.org/aspectj/downloads.php#ides[AspectJ Development Tools]をダウンロードできます。 AJDTの最も重要な機能の1つは、横断的な問題を視覚化するためのツールです。これは、ポイントカット仕様をデバッグするのに役立ちます。コードがデプロイされる前でも組み合わせ効果を視覚化することがあります。

私たちはMojoのAspectJ Mavenプラグインを使って、AspectJコンパイラを使ってAspectJアスペクトをクラスに織り込みます。

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.7</version>
    <configuration>
        <complianceLevel>1.8</complianceLevel>
        <source>1.8</source>
        <target>1.8</target>
        <showWeaveInfo>true</showWeaveInfo>
        <verbose>true</verbose>
        <Xlint>ignore</Xlint>
        <encoding>UTF-8 </encoding>
    </configuration>
    <executions>
        <execution>
            <goals>
                <!-- use this goal to weave all your main classes -->
                <goal>compile</goal>
                <!-- use this goal to weave all your test classes -->
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

AspectJコンパイラのオプション参照の詳細については、次のhttp://www.mojohaus.org/aspectj-maven-plugin/ajc reference/standard opts.html[link]を調べてください。

Accountクラスのテストケースをいくつか追加しましょう。

public class AccountTest {
    private Account account;

    @Before
    public void before() {
        account = new Account();
    }

    @Test
    public void given20AndMin10__whenWithdraw5__thenSuccess() {
        assertTrue(account.withdraw(5));
    }

    @Test
    public void given20AndMin10__whenWithdraw100__thenFail() {
        assertFalse(account.withdraw(100));
    }
}

テストケースを実行すると、コンソールに表示される以下のテキストは、ソースコードの作成に成功したことを意味します。

----[INFO]Join point 'method-call
(boolean com.baeldung.aspectj.Account.withdraw(int))' in Type
'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20)
advised by around advice from 'com.baeldung.aspectj.AccountAspect'
(AccountAspect.class:18(from AccountAspect.aj))
[INFO]Join point 'method-call
(boolean com.baeldung.aspectj.Account.withdraw(int))' in Type
'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20)
advised by before advice from 'com.baeldung.aspectj.AccountAspect'
(AccountAspect.class:13(from AccountAspect.aj))
[INFO]Join point 'method-call
(boolean com.baeldung.aspectj.Account.withdraw(int))' in Type
'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20)
advised by after advice from 'com.baeldung.aspectj.AccountAspect'
(AccountAspect.class:26(from AccountAspect.aj))

2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Balance before withdrawal: 20 2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Withdraw ammout: 5 2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Balance after withdrawal : 15 2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Balance before withdrawal: 20 2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Withdraw ammout: 100 2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Withdrawal Rejected! 2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.AccountAspect - Balance after withdrawal : 20

===  **  6. コンパイル後の製織**

コンパイル後のウィービング(バイナリウィービングとも呼ばれる)は、既存のクラスファイルとJARファイルをウィーブするために使用されます。コンパイル時のウィービングと同様に、ウィービングに使用されるアスペクトはソース形式でもバイナリ形式でもよく、それ自体アスペクトによって織られている場合があります。

MojoのAspectJ Mavenプラグインを使ってこれを行うには、プラグイン設定に入れたいJARファイルをすべてセットアップする必要があります。

[source,xml,gutter:,true]

<configuration> <weaveDependencies> <weaveDependency> <groupId>org.agroup</groupId> <artifactId>to-weave</artifactId> </weaveDependency> <weaveDependency> <groupId>org.anothergroup</groupId> <artifactId>gen</artifactId> </weaveDependency> </weaveDependencies> </configuration>

編むクラスを含むJARファイルは、Mavenプロジェクトでは `<dependencies/>`としてリストされ、AspectJ Mavenプラグインの `<configuration>`では `<weaveDependencies/> 'としてリストされる必要があります。

===  **  7. ロードタイムウィービング**

ロード時のウィービングは、クラスローダーがクラスファイルをロードしてクラスをJVMに定義するまでは、単純にバイナリウィービングです。

これをサポートするには、1つ以上の「ウィービングクラスローダー」が必要です。これらはランタイム環境によって明示的に提供されるか、または「ウィービングエージェント」を使用して有効にされます。

====  **  7.1. ロードタイムウィービングを有効にする**

AspectJロードタイムウィービングは、クラスローディングプロセスに参加し、VMで定義される前に任意のタイプを織り込むことができるAspectJエージェントを使用して有効にすることができます。 JVMの `__-javaagent:pathto/aspectjweaver.jar`__に__javaagent__オプションを指定するか、Mavenプラグインを使用して__javaagent__を設定します。

[source,xml,gutter:,true]

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.10</version> <configuration> <argLine> -javaagent:"${settings.localRepository}"/org/aspectj/ aspectjweaver/${aspectj.version}/ aspectjweaver-${aspectj.version}.jar </argLine> <useSystemClassLoader>true</useSystemClassLoader> <forkMode>always</forkMode> </configuration> </plugin>

====  **  7.2. 設定ウィーバー**

AspectJのロードタイムウィービングエージェントは__aop.xml__ファイルを使って設定されます。 __META-INF__ディレクトリ内のクラスパスで1つ以上の__aop.xml__ファイルを探し、その内容を集計してウィーバー設定を決定します。

__aop.xml__ファイルには、2つの重要なセクションがあります。

**  ** アスペクト** :ウィーバーとコントロールに1つ以上のアスペクトを定義します

織る過程でどの側面を使うべきかその側面
elementは、オプションで1つ以上の__include__と__exclude__を含むことができます。
要素(デフォルトでは、定義されたすべてのアスペクトが製織に使用されます)
**  **  Weaver ** :ウィーバーに対するウィーバーオプションを定義し、セットを指定します

織るべきであるタイプの。 include要素が指定されていない場合は、ウィーバーに表示されるすべてのタイプが織られます。

ウィーバーにアスペクトを設定しましょう。

[source,xml,gutter:,true]

<aspectj> <aspects> <aspect name="com.baeldung.aspectj.AccountAspect"/> <weaver options="-verbose -showWeaveInfo"> <include within="com.baeldung.aspectj.** "/> </weaver> </aspects> </aspectj>

ご覧のとおり、__AccountAspect__を指すアスペクトを構成しており、__com.baeldung.aspectj__パッケージ内のソースコードのみがAspectJによって編まれることになります。

===  **  8アノテーションを付ける**

おなじみのAspectJコードベースのアスペクト宣言のスタイルに加えて、AspectJ 5はアノテーションベースのアスペクト宣言のスタイルもサポートしています。この開発スタイルをサポートする一連の注釈を「__ @ AspectJ__」注釈と呼びます。

注釈を作成しましょう。

[source,java,gutter:,true]

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Secured { public boolean isLocked() default false; }

メソッドを有効または無効にするには、__ @ Secured__アノテーションを使用します。

[source,java,gutter:,true]

public class SecuredMethod {

@Secured(isLocked = true)
public void lockedMethod() {
}
    @Secured(isLocked = false)
    public void unlockedMethod() {
    }
}
次に、AspectJ annotation-styleを使用してアスペクトを追加し、@ Securedアノテーションの属性に基づいて権限を確認します。

[source,java,gutter:,true]

@Aspect public class SecuredMethodAspect { @Pointcut("@annotation(secured)") public void callAt(Secured secured) { }

    @Around("callAt(secured)")
    public Object around(ProceedingJoinPoint pjp,
      Secured secured) throws Throwable {
        return secured.isLocked() ? null : pjp.proceed();
    }
}
AspectJアノテーションスタイルの詳細については、//eclipse.org/aspectj/doc/released/adk15notebook/annotations-aspectmembers.html[link]を参照してください。

次に、ロードタイムウィーバーを使用してクラスとアスペクトを織り込み、__Mop-INF__フォルダーの下に__aop.xml__を置きます。

[source,xml,gutter:,true]

<aspectj> <aspects> <aspect name="com.baeldung.aspectj.SecuredMethodAspect"/> <weaver options="-verbose -showWeaveInfo"> <include within="com.baeldung.aspectj.** "/> </weaver> </aspects> </aspectj>

最後に、単体テストを追加して結果を確認します。

[source,java,gutter:,true]

@Test public void testMethod() throws Exception { SecuredMethod service = new SecuredMethod(); service.unlockedMethod(); service.lockedMethod(); }

テストケースを実行するときに、コンソールの出力をチェックして、アスペクトとクラスをソースコードに正しく作成したことを確認できます。

[source,java,gutter:,true]

----[INFO]Join point 'method-call
(void com.baeldung.aspectj.SecuredMethod.unlockedMethod())'
in Type 'com.baeldung.aspectj.test.SecuredMethodTest'
(SecuredMethodTest.java:11)
advised by around advice from 'com.baeldung.aspectj.SecuredMethodAspect'
(SecuredMethodAspect.class(from SecuredMethodAspect.java))

2016-11-15 22:53:51[main]INFO com.baeldung.aspectj.SecuredMethod
- unlockedMethod
2016-11-15 22:53:51[main]INFO c.b.aspectj.SecuredMethodAspect -
public void com.baeldung.aspectj.SecuredMethod.lockedMethod() is locked

9結論

この記事では、AspectJについての紹介概念について説明しました。詳細については、https://eclipse.org/aspectj/[AspectJのホームページをご覧ください。]

あなたはこの記事のソースコードを見つけることができますhttps://github.com/eugenp/tutorials/tree/master/spring-aop[over on GitHub]。