図3●MessageServletの実行結果。コンポーネント定義ファイルに記述する実装クラスを変えるだけで実行結果が変わる
図3●MessageServletの実行結果。コンポーネント定義ファイルに記述する実装クラスを変えるだけで実行結果が変わる
[画像のクリックで拡大表示]
リスト2●IMessageインタフェースのソースコード
リスト2●IMessageインタフェースのソースコード
[画像のクリックで拡大表示]
リスト3●実装クラスのMorningMessageImplクラスのソースコード
リスト3●実装クラスのMorningMessageImplクラスのソースコード
[画像のクリックで拡大表示]
リスト4●実装クラスのNightMessageImplクラスのソースコード
リスト4●実装クラスのNightMessageImplクラスのソースコード
[画像のクリックで拡大表示]
リスト5●複数のコンポーネント定義ファイルを管理するルート定義ファイルであるapp.diconの内容(抜粋)
リスト5●複数のコンポーネント定義ファイルを管理するルート定義ファイルであるapp.diconの内容(抜粋)
[画像のクリックで拡大表示]
リスト6●具体的なコンポーネントの登録を行うコンポーネント定義ファイルのMessage.diconの内容(抜粋)。今回のサンプルでは,このファイルを変更するだけで実行結果を変えられる
リスト6●具体的なコンポーネントの登録を行うコンポーネント定義ファイルのMessage.diconの内容(抜粋)。今回のサンプルでは,このファイルを変更するだけで実行結果を変えられる
[画像のクリックで拡大表示]
リスト7●Seasar2を呼び出すMessageServletのソースコード。実装クラス名も実装クラスの初期化コードも一切含まれていない
リスト7●Seasar2を呼び出すMessageServletのソースコード。実装クラス名も実装クラスの初期化コードも一切含まれていない
[画像のクリックで拡大表示]

インタフェースの実装クラスはコンポーネント定義ファイルに登録

 それでは,簡単なサンプル・コードを使ってSeasar2の動作を確認してみましょう。ここで紹介するのは「サーブレットMessageServletからMessageコンポーネントを呼び出し,指定されたメッセージを表示する」というごく基本的なアプリケーションです。「http://localhost:8080/nikkei200509/MessageServlet」にアクセスすると(図3[拡大表示])右上のようにメッセージが表示されます。

 Seasar2のようなDIコンテナを利用する場合,まずコードの中で利用するインタフェースと具体的な実装クラス(コンポーネント)を用意する必要があります。サンプルでは,インタフェースとしてIMessage(リスト2[拡大表示]),実装クラスとしてMorningMessageImpl(リスト3[拡大表示])とNightMessageImpl(リスト4[拡大表示])を用意しました。IMessageは,getMessage,setMessageという二つのアクセサ・メソッドを定義した単純なインタフェースです。

 次に,実装クラスをDIコンテナに登録します。DIコンテナは,プログラムの中で利用されているインタフェースに対して具体的な実装クラスを割り当てます。このため,利用する実装クラスのコンポーネントをあらかじめ宣言しておく必要があるのです。

 Seasar2では,コンポーネント登録を行うのは「.dicon」という拡張子を持つコンポーネント定義ファイルの役割です。サンプルでは,コンポーネント定義ファイルとして,app.dicon(リスト5[拡大表示])とMessage.dicon(リスト6[拡大表示])を用意しました。これらは/WEB-INF/classesフォルダに配置します。

 app.diconは,リスト1(1)に示したように,デプロイメント・ディスクリプタにサーブレット初期化パラメータとして登録したファイルです。役割は,アプリケーション内で分散した複数のコンポーネント定義ファイルを管理するための「ルート定義ファイル」です*7。アプリケーション内で必要とするコンポーネント定義ファイルを<include>要素でインクルードしています。path属性は/WEB-INF/classesフォルダからの相対パスを指定します。複数のコンポーネントを定義する場合には,<include>要素を複数列記します。

 具体的なコンポーネントの登録は,app.diconでインクルードされる個別の「.dicon」ファイルで行います。サンプルではMessage.dicon(リスト6)がこれにあたります。<component>要素のclass属性に,DIコンテナに登録したいコンポーネントを完全修飾名で指定します。コンポーネントを初期化する際に引き渡すパラメータは<property>要素で指定できます。

 DIコンテナの特徴として,設定ファイルを記述するだけでコンポーネントの初期化処理を自動的に行ってくれる点があります。DIコンテナは,定義された引数の型と定義ファイルに登録されたコンポーネントから動的に判定し,適切なコンポーネントを利用して初期化処理を行います。

 ちなみに,ここではMorningMessageImplクラスのsetMessageメソッドに対して,Message.diconでmessageプロパティとして定義した「Nikkei Taro」という値を引き渡しています。このような値引き渡しを「セッタ注入」と言います*8。Seasar2ではこのほかに,コンストラクタを介してコンポーネントの初期化を行う「コンストラクタ注入」,指定された任意のメソッドを介して初期化を行う「メソッド注入」という方法を利用できます。

設定ファイルの変更だけで実行するコードを変えられる

 Seasar2を動かすのに必要な準備がわかったところで,実際にSeasar2を呼び出すMessageServletの内容を見てみましょう(リスト7[拡大表示])。Seasar2を呼び出すには,S2ContainerServlet#getContainerメソッドを使用します(リスト7(1))。個々のコンポーネントは,S2Container#getComponentメソッドで取得できます(リスト7(2))。

 ここで注目していただきたいのは,サーブレットのコードには実装クラス名も実装クラスの初期化コードも「一切含まれていない」ことです。つまり,コンポーネントの割り当てをDIコンテナに任せることで,実装クラスを変更する場合にコードを修正する必要がなくなります。

 今回のサンプルでは,Message.dicon(リスト6)の<component>要素のclass属性を書き換えるだけで実行結果を変更できることを確認できます。リスト6の(1)をMorningMessageImplからNightMessageImplに書き換え,Seasar2を再起動したうえでMessageServletにアクセスすると,Javaのコードをまったく書き換えていないにもかかわらず,異なるコードが実行され,表示する文字列が変わります(図3右下)。


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

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