表3●Seasar2の動作に最低限必要なファイル
表3●Seasar2の動作に最低限必要なファイル
[画像のクリックで拡大表示]
リスト4●サンプルのインタフェースであるlHello.java
リスト4●サンプルのインタフェースであるlHello.java
[画像のクリックで拡大表示]
リスト5●サンプルの実装クラスであるlHello.java
リスト5●サンプルの実装クラスであるlHello.java
[画像のクリックで拡大表示]
リスト6●Seasar2の設定ファイルであるHello.dicon
リスト6●Seasar2の設定ファイルであるHello.dicon
[画像のクリックで拡大表示]
リスト7●実装クラスを呼び出すHelloClient.java
リスト7●実装クラスを呼び出すHelloClient.java
[画像のクリックで拡大表示]
リスト8●インタセプタであるLoggingInterceptor.java
リスト8●インタセプタであるLoggingInterceptor.java
[画像のクリックで拡大表示]
リスト9●アスペクトを織り込む場合のHello.dicon(一部)
リスト9●アスペクトを織り込む場合のHello.dicon(一部)
[画像のクリックで拡大表示]
図8●Seasar2によるアスペクトの織り込み
図8●Seasar2によるアスペクトの織り込み
[画像のクリックで拡大表示]
図9●サンプルを実行してアスペクトを織り込んだところ
図9●サンプルを実行してアスペクトを織り込んだところ
[画像のクリックで拡大表示]

アスペクトを実行時に織り込むSeasar2

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

 さて今度はSeasar2を見ていきましょう。まず,SeasarプロジェクトのWebサイト(http://www.seasar.org/)から「S2.2.10.zip」をダウンロードします。解凍すると「seasar2」フォルダができます。最小限必要なファイルを(表3[拡大表示])に示しました。それぞれのjarファイルのパスとlog4j.propertiesが存在するディレクトリのパスを環境変数CLASSPATHに追加してください*5

(2)織り込む対象を用意する

 先ほどと同様に,アスペクトを織り込む対象になるアプリケーションを作成します。2005年9月号の連載第3回で紹介したように,軽量コンテナを利用するには,まずコード内で利用するインタフェースと具体的な実装クラスを用意する必要があります。そこで,インタフェースとしてIHello.java(リスト4[拡大表示]),実装クラスとしてIHelloImpl.java(リスト5[拡大表示])を用意します。実装クラスであるIHelloImpl.javaは,Hello.dicon(リスト6[拡大表示])という設定ファイルを使ってSeasar2に登録します*6

 IHelloImplを呼び出して実行するのが,HelloClient.java(リスト7[拡大表示])です。S2ContainerFactory#createメソッドでSeasar2を取得した後,登録されたコンポーネントをgetComponentメソッドで取得しています。HelloClientクラスを実行すると「Hello, World!!」と表示されます。

(3)アスペクトを組み込む

 次に,このアプリケーションに対して,アスペクトを組み込んでみましょう。

 Seasar2では,AspectJとは異なり,インタセプタを記述するのに特別なアスペクト構文を利用する必要はありません。Seasar2でインタセプタを定義するには,AbstractInterceptorクラスを継承したサブクラスを定義します。サンプルではLoggingInterceptor.java(リスト8[拡大表示])というファイルになります。

 インタセプタの実際の処理を記述するのはinvokeメソッドの役割です。invokeメソッドに引き渡されるMethodInvocationオブジェクトは,結合点のメソッド情報を管理するオブジェクトです。MethodInvocationオブジェクトを介することで,メソッドそのものやメソッドの引数情報を取得することが可能です。

 invokeメソッドでは,最後にMethodInvocation#proceedメソッドによる戻り値を返すのが基本です。proceedメソッドは,織り込み先のメソッドを呼び出し,その結果を返します。複数のインタセプタが織り込まれている場合は,proceedメソッドは次に実行すべきインタセプタを呼び出します。

 次に,インタセプタを織り込むべきポイント・カットを指定します。Seasar2では,ポイント・カットの指定に,標準の設定ファイルである「.diconファイル」を使います。(リスト9[拡大表示])は,アスペクトの設定を追加したHello.diconファイルです。<component>要素でインタセプタをSeasar2上に登録します。その際,ほかの個所から参照できるようにname属性を指定するのを忘れないようにしてください。

 コンポーネントへの織り込みは,<aspect>要素で行います。pointcut属性に織り込み先のポイント・カットを指定し,本体には織り込むインタセプタの名前を記述します。インタセプタ名は,先の<component>要素のname属性で指定した名前になります。ポイント・カットの記述には,「get.*」といったように正規表現を使うことも可能です。複数の正規表現を指定する場合は「get.*,set.*」のようにカンマで区切って並べてください。複合的なポイント・カットを設定したい場合には,複数の<aspect>要素を記述することも可能です。

 これまでに述べたように,Seasar2ではアスペクトを「AbstractInterceptorサブクラスと設定ファイルのセット」として表現します。AspectJのように特別なアスペクト構文を習得する必要がないのがメリットです。

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

 最後に,アスペクトを織り込んだサンプルを実行してみましょう。Seasar2ではコンパイルに特別なツールは必要ありません。標準のjavacを使います。ビジネス・ロジックをコンパイルし直す必要もありません。先ほどのサンプルに,javacでコンパイルしたLoggingInterceptorクラスを追加し,Hello.diconを差し替えればOKです。HelloClientクラスを実行すると,動的にアスペクトが織り込まれます(図8[拡大表示])。この結果,showMessageメソッドによる出力の前に,インタセプタによってログのメッセージが出力されます(図9[拡大表示])。

 Seasar2のように実行時に織り込みを行うとパフォーマンス劣化の原因になる場合があります。ただ,この程度の処理であれば遅延はほとんど問題にならないでしょう。

☆               ☆               ☆

 今回は,AspectJとSeasar2という二つのオープンソース・ソフトウエアを利用して,アスペクト指向プログラミングに挑戦してみました。いずれも,オリジナルのビジネス・ロジックのコードを変更することなく,容易に機能を追加できることがおわかりになったと思います。

 ただし,二つのソフトウエアを比べてもわかるように,アスペクトを織り込むためのアプローチは,ソフトウエアによって大きく異なります。AspectJは独自の構文を採用しているのに対し,Seasar2は標準的なJavaクラスを利用します。また,AspectJではアスペクトを織り込むためにコンパイル時に専用ツールajcが必要ですが,Seasar2のアスペクトはJDKの標準ツールであるjavac/javaのみで利用できます。一方,AspectJを使って作られたクラスは通常のJavaアプリケーションとして実行可能ですが,Seasar2では実行時にコンテナを介してアスペクトとアプリケーション本体を関連付ける必要があります。こうした違いを理解するとともに,アスペクト指向の持つ可能性を感じ取っていただければ幸いです。


表A●Hibernateの動作に必要なファイル
[画像のクリックで拡大表示]

AspectJによる開発を支援するEclipseプラグイン

 アスペクト指向では,アスペクトがどこに埋め込まれるかがメインのビジネス・ロジックに記述されないため,動作を追うのが面倒な場合があります。こうしたときに威力を発揮するのが,アスペクトが織り込まれる位置を確認できる支援ツールです。

 AspectJでよく使われているのが,「AJDT(AspectJ Development Tools)」というEclipseのプラグインです(図A[拡大表示])。AJDTプロジェクトのサイト(http://www.eclipse.org/ajdt/downloads/)からダウンロードできます。

 EclipseでAJDTを利用する際には,新規プロジェクトとして「AspectJプロジェクト」を選択します。AspectJプロジェクト環境では,アスペクトの編集/コンパイルはもちろん,キーワードのハイライト表示やアスペクトとJavaクラスとのマッピングの確認ができます。

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

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