このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

AspectJを使いはじめよう

ひとつ前のエントリー:

僕はだいぶ以前から、いくつか(複数)の理由からAOPには興味があったのだけど、たまに横目で眺めている傍観者って感じで、自分で調べる気力が湧かなかったんだけど、ちょっと刺激されました。

んで、とりあえず、最近のAspectJコンパイラを使えるようにしましたよ。

ダウンロードとセットアップ

AspectJのWebサイトダウンロードページから、最新安定版(Latest Stable Release)である「AspectJ 1.5.0, Released 20th December, 2005」をダウンロード。

ファイルはaspectj-1.5.0.jarですが、これ自体がJavaで書かれたインストーラなので、


java -jar aspectj-1.5.0.jar
としてインストールできます。すっげーお手軽で、これで好感を持ちました。

環境変数PATHとCLASSPATHを設定しておいたほうがいいです。例えば、AspectJのインストール先がC:\Java\aspectj1.5\だとして、

  1. PATHに、C:\Java\aspectj1.5\binを加える。
  2. CLASSPATHに、C:\Java\aspectj1.5\lib\aspectjrt.jarを加える。

コンパイラコマンドはajcシェルスクリプトまたはバッチファイル)ですね。これを一回実行すれば、環境変数ASPECTJ_HOMEを(JAVA_HOMEも)設定してくれます。

%ASPECTJ_HOME%\doc\index.htmlからたどれるドキュメントはかなり充実している模様。%ASPECTJ_HOME%\doc\example\の下にサンプルもあります。

コンパイラの使い方

%ASPECTJ_HOME%\doc\examples\ltwに簡単な定番サンプルがあります(ltwはload-time weavingのサンプルですが、気にしないで借用)。


/* HelloWorld.java */
public class HelloWorld {
public static void main (String[] args) {
System.out.println("Hello World!");
}
}


/* Tracing.java */
public aspect Tracing {
private pointcut mainMethod () :
execution(public static void main(String[]));

before () : mainMethod() {
System.out.println("> " + thisJoinPoint);
}

after () : mainMethod() {
System.out.println("< " + thisJoinPoint);
}
}

まず、ajcはjavacの代わりに使えます。


C:\tmp>set CLASSPATH=%CLASSPATH%;.

C:\tmp>ajc HelloWorld.java

C:\tmp>java HelloWorld
Hello World!

C:\tmp>

javacではコンパイルできないAspectJ固有のコードもコンパイルできます。


C:\tmp>javac Tracing.java
Tracing.java:2: 'class' または 'interface' がありません。
public aspect Tracing {
^
エラー 1 個

C:\tmp>ajc Tracing.java

C:\tmp>

しかし、クラスとアスペクトを個別にコンパイルしても、新しいことは何も起きません。アスペクト(この場合はTracing)をクラス(この場合はHelloWorld)に織り込むには次のようにします。


C:tmp>ajc HelloWorld.java Tracing.java

C:\tmp>java HelloWorld
> execution(void HelloWorld.main(String[]))
Hello World!
< execution(void HelloWorld.main(String[]))

C:\tmp>

ajcに指定するソースファイルの順序は問いません。ajc *.javaでもOKです。ワイルドカードは次のようにも使えますね。


C:\tmp>mkdir src

C:\tmp>copy HelloWorld.java src
1 個のファイルをコピーしました。

C:\tmp>mkdir aspects

C:\tmp>copy Tracing.java aspects
1 個のファイルをコピーしました。

C:\tmp>ajc src/*.java aspects/*.java

C:\tmp>java -classpath %CLASSPATH%;src;aspects HelloWorld
> execution(void HelloWorld.main(String[]))
Hello World!
< execution(void HelloWorld.main(String[]))

C:\tmp>

でも、上の方法ではクラスファイルが別々の場所に作られるので、次のほうがいいでしょう。


C:\tmp>mkdir classes

C:\tmp>ajc -d classes src/*.java aspects/*.java

C:\tmp>java -classpath %CLASSPATH%;classes HelloWorld
> execution(void HelloWorld.main(String[]))
Hello World!
< execution(void HelloWorld.main(String[]))

C:\tmp>

ワイルドカードを使わずとも、ソースディレクトリを指定することもできます。


C:\tmp>ajc -d classes -sourceroots src;aspects

C:\tmp>set CLASSPATH=%CLASSPATH%;.\classes

C:\tmp>java HelloWorld
> execution(void HelloWorld.main(String[]))
Hello World!
< execution(void HelloWorld.main(String[]))

C:\tmp>

既に作成されているjarファイルに、アスペクトを後から織り込むこともできます。


C:\tmp>javac -d . src\HelloWorld.java

C:\tmp>jar cvf HelloWorld.jar HelloWorld.class
マニフェストが追加されました。
HelloWorld.class を追加中です。(入 = 426) (出 = 288)(32% 収縮されました)

C:\tmp>ajc -d classes -injars HelloWorld.jar aspects/*.java

C:\tmp>java HelloWorld
> execution(void HelloWorld.main(String[]))
Hello World!
< execution(void HelloWorld.main(String[]))

C:\tmp>

上のコマンドでは、HelloWorld.jarに含まれる各クラスに、コンパイルされたアスペクトが織り込まれ、結果として織り込み済みクラスファイルが生成されます。jarファイル自体は変更されません。出力も再びjarファイルにしたいなら、-outjarオプション(outjarsではないから注意)が使えます。