minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

AspectJプロジェクトの作成

まず、サンプルプロジェクトを作成します。
メニューの「File->New」から「AspectJ Project」を選択して下さい。

そして、サンプルとなるクラスを作ります。パッケージはどこでも構いません。

public class Sample1 {
    
    public static void main(String[] args) {
        new Sample1().func1();
    }
    
    private void func1() {
        System.out.println("run func1.");
    }
}

メソッド func1 を呼び出すだけの単純なものです。
このプログラムの実行結果は以下のようになります。

run func1.

アスペクト指向の取り入れ

では、このプログラムにアスペクト指向を取り入れてみます。
Sample1と同じパッケージに、「AspectSample1.java」というファイルを作成します。
内容は以下のようにします。

aspect AspectSample1 {
    
    pointcut atFunc1() : call(void Sample1.func1());
    
    before() : atFunc1() {
        System.out.println("before func1.");
    }
    after() : atFunc1() {
        System.out.println("after func1.");
    }
}

拡張子はjavaですが、トップ要素は「class」ではなく「aspect」にします。
このように、アスペクトファイルはjavaファイル中に記述する形になります。
よって、通常のJavaコンパイラではコンパイルできません。
そういった意味で、アスペクトファイルは別パッケージに記述するのも
一つの手法かと思います。
もしくは、アスペクトファイルをajという拡張子にします。

サンプルアスペクトファイルの内容は、3つのブロックに分かれています。
アスペクト名(ここではAspectSample1)は任意で構いません。
それでは、ブロックを一つずつ解説します。

pointcut

アスペクト指向では、
「あるプログラムコードを実行する前後に特定のロジックを実行する」
という流れが主になります。
このプログラムコードのことをAspectJでは Join Point と呼びます。

サンプルプログラムの第1ブロックで、Join Pointを定義しています。

call(void Sample1.func1())

Sample1 クラスの void func1() メソッドを呼び出す箇所に、Join Point を設定します。
このとき、call というキーワードを用います。

ここでは、pointcut というキーワードも使っています。
これは、このJoin Pointに「atFunc1」という名前を付けるという指示になります。
「atFunc1」はJavaのメソッド名定義ではありません。

「Sample1.func1」のようにパッケージ名を省略して記述すると、
アスペクトファイルと同一パッケージのクラスが対象になります。
異なるパッケージのクラスを使用する場合、クラス名を完全限定名で記述する必要があります。
クラス名を省略すると、全クラスの同名メソッドが対象となります。

今回の例では、戻り値がvoid以外だったり引数を取ったりするfunc1メソッドは
対象となりません。
このように、戻り値と引数の個数や型は省略せずに記述する必要があります。
後述しますがワイルドカードの使用も可能です。

advice

Join Point到達時に実行するロジックを定義しているのが、第2・第3ブロックです。
どちらも、第1ブロックで定義したPointCut(atFunc1)に関するものです。
AspectJでは、あるJoin Pointに関して
ロジックを実行するタイミング(や動作)を3タイプの中から設定できます。
タイプはそれぞれ、before / after / around というキーワードを用います。

before

Join Point のコードを実行する前に走らせるロジックを定義します。

after

Join Point のコードを実行した後に走らせるロジックを定義します。

around

Join Point のコードの替わりに走らせるロジックを定義します。
ロジックを実行するタイミングとしては before と同じになりますが、
このロジックを実行した後で本来のコードが実行されません。
その後、すぐに after で定義したロジックが実行されることになります。

なお、aroundロジック中に proceed() というメソッドを呼び出すことによって
本来のコードを実行することも出来ます。

サンプルでは、beforeafter を定義しています。
AspectJでは、これらのロジックの事を advice と呼びます。

サンプルの実行

さて、ここで再び Sample1 クラスを実行してみましょう。
結果は以下のようになります。

before func1.
run func1.
after func1.

確かに、func1メソッドを呼び出すコードの前後で
before / after の各ロジックが実行されている事がわかります。

Sample1.javaファイルをAspectJエディタで開くと、func1メソッドの呼び出し箇所に
マーカーが付いているのが確認できると思います。
「定義箇所」ではなく「呼び出し箇所」というのがミソです。

call 代わりに execution キーワードを用いると、
定義箇所にマーカーが付きます。
もちろん、マーカーだけでなくこの2つのキーワードは
動作の面でも若干異なります。

プラグインインストール時の注意

AspectJプラグインをインストールすると、
javaファイルに関連付けられるエディタが「AspectJ/Java Editor」になります。
このエディタはJava Editorとほぼ同じなのですが、
Quick Fix などが正常に動作しません。

さらに、AspectJプロジェクト内のファイルを通常のJava Editorで開いた場合にも
これらが動作しなくなってしまうようです(Eclipse3.0.0 / AJDT1.1.12 で確認)。

ですので、AspectJプラグインは
別ディレクトリに格納してインストールするのが良いでしょう。
こうすれば、簡単にプラグインの取り外しが可能になります。