図4●AspectJのインストーラ
図4●AspectJのインストーラ
[画像のクリックで拡大表示]
リスト1●アスペクト織り込み用サンプルのHello.java
リスト1●アスペクト織り込み用サンプルのHello.java
[画像のクリックで拡大表示]
リスト2●アスペクト織り込み用サンプルのHelloSample.java
リスト2●アスペクト織り込み用サンプルのHelloSample.java
[画像のクリックで拡大表示]
図5●サンプルをコンパイル/実行したところ
図5●サンプルをコンパイル/実行したところ
[画像のクリックで拡大表示]
リスト3●アスペクトのファイルであるLoggingAspect.java
リスト3●アスペクトのファイルであるLoggingAspect.java
[画像のクリックで拡大表示]
表2●AspectJの結合点の記述に利用できる主な定義済みタイプ
表2●AspectJの結合点の記述に利用できる主な定義済みタイプ
[画像のクリックで拡大表示]
図6●ajcによるコンパイルとクラス・ファイルの実行
図6●ajcによるコンパイルとクラス・ファイルの実行
[画像のクリックで拡大表示]
図7●AspectJによるアスペクトの織り込み
図7●AspectJによるアスペクトの織り込み
[画像のクリックで拡大表示]

AspectJでアスペクトを体験

(1)AspectJをインストールする

 それではAspectJを使ってみましょう。まず,Eclipse.orgのAspectJプロジェクトのページ(http://www.eclipse.org/aspectj/)から「aspectj-1.2.1.jar」をダウンロードします。このファイルにはインストーラが含まれています。コマンドプロンプトから

java -jar aspectj-1.2.1.jar

というコマンドを実行すると,図4[拡大表示]のようなインストーラが起動します。インストールが終わると,AspectJの実行に必要なライブラリが「C:\aspectj1.2」に展開されます*3
(2)織り込む対象を用意する

 次に,アスペクトを織り込む対象になるアプリケーションを作成します。Hello.java(リスト1[拡大表示])とHelloSample.java(リスト2[拡大表示])です。HelloSampleクラスからHello#showMessageメソッドを呼び出すという簡単なアプリケーションです。javacコマンドでコンパイルし,HelloSampleクラスを実行すると「Hello, World!!」というメッセージが表示されます(図5[拡大表示])。

(3)アスペクトを記述する

 このアプリケーションに対し,「Hello, World!!」を表示するタイミングで標準出力にログを表示する単純なアスペクトを織り込んでみましょう。

 従来のオブジェクト指向でこうした機能を実現しようとすると,ログ出力(またはログ出力機能の呼び出し)のコードをHelloSampleクラスに追加することになります。ところがアスペクト指向では,アプリケーションのコードにはまったく手を加える必要がありません。ログ機能と挿入ポイントを定義する「アスペクト」を,アプリケーションのコードとは独立して作成できます。

 ロギングのアスペクトであるLoggingAspect.javaは(リスト3[拡大表示])のようになります*4。一見,Javaのコードのようですが,よく見ると独自の構文が使われていることがわかります。

 AspectJでどのようにアスペクトを記述するかを見ていきましょう。まず,「aspect」というキーワードでアスペクトを定義します。アスペクトの中には,ポイント・カットとインタセプタをセットで記述します。

 ポイント・カットは「pointcut」というキーワードで定義します。一般的な構文は,

[修飾子] pointcut ポイント・カット名([引数]) : 結合点
のようになります。

 前に説明したように,ポイント・カットは一つ以上の結合点の集合です。結合点には,(表2[拡大表示])に示したような定義済みのタイプを指定できます。タイプの引数には,織り込み先を表すシグネチャを指定します。シグネチャには「*」(「.」を含まない任意の文字列)や「..」(「.」を含む任意の文字列)などのワイルドカードを含むことができます。また,タイプを「&&」(AND),「││」(OR),「!」(NOT)のような論理演算子で連結したり,ifキーワードで条件式を定義することで,より複雑なポイント・カットを指定できます。アスペクト指向実装の良し悪しはポイント・カットの記述性によって決まります。AspectJはワイルドカードや演算子により柔軟なポイント・カットを定義できるのが特徴です。

 リスト3では,callという定義済みタイプを使い,Hello#showMessageメソッドが呼び出されるタイミングをshowMessageという名前のポイント・カットとして定義しています。

 定義したポイント・カットに対して,織り込むインタセプタを記述します。リスト3にある「before」は,ポイント・カットの直前,つまりshowMessageメソッドが呼び出される直前に,インタセプタを処理することを意味します。AspectJでは,beforeのほかに,ポイント・カットの直後に実行される「after」,ポイント・カットのブロックを置き換える「around」などのキーワードを利用できます。ここでは,「showMessageポイント・カット」=「Hello#showMessageメソッドが呼び出される直前」に,「showMessageメソッドを呼び出します。」というログのメッセージを出力するインタセプタを設定しています。

(4)アスペクトを実行する

 では,いよいよアスペクトを織り込んだサンプルを実行してみましょう。AspectJでは,コンパイル時にアスペクトを織り込むので,コンパイルにはJDK付属のjavacではなく,AspectJに付属している専用ツール「ajc」を使用します。ajcでアスペクトとアプリケーションのコードを同時に処理することにより,アスペクトを織り込んだJavaのクラス・ファイルが作成されます(図6[拡大表示](1),図7[拡大表示])。

 ajcによる処理が終わると,javacによる通常のコンパイルと同様に,「.class」の拡張子を持つクラス・ファイルが生成されます。このクラス・ファイルは,アスペクトを織り込み済みの普通のJavaクラスなので,JDK付属のjavaコマンドで実行できます。実行すると,showMessageメソッドによる出力の前に,インタセプタがログを出力します(図6[拡大表示](2))。


山田 祥寛(やまだ よしひろ)

千葉県鎌ヶ谷市在住のフリーライター(http://www.wings.msn.to/