設定ファイルを階層構造に

図4●自動発見のスコープを限定
Seasar2は,登録された実装クラスをコンテナが自動的に検索,発見する。基本的にインタフェースの名前で識別する。このとき,同じ名前のインタフェースを実装したクラスが複数あると,どのクラスのオブジェクトを依存性のあるものと見なしてよいか判断がつかない。この問題を避けるため,Seasar2はコンポーネントの登録情報を階層別に分別する仕組みを備えている。オブジェクトを検索するスコープを限ることで,衝突の危険性を軽減する。親となるコンテナは,自分と,自分の子となるコンテナが管理するオブジェクトだけを検索の対象とする。ただし,階層の作り方によってはオブジェクトの重複は発生する。例えばAのコンテナがNameインタフェースを実装したオブジェクトを検索すると,重複が起こるため例外が発生する。
リスト●EJB 3.0におけるDI
簡単な宣言をクラス中に記述することでオブジェクトの定義をする「アノテーション」を使って,DIを実現する。ここでは「@Resource」や「@Inject」というアノテーションを記述して,データベースのデータソースと,他のオブジェクトを指定している。アノテーション記述は,EJB 3.0のEarly Draft版の仕様書から引用。

 他のDIコンテナも基本的にSeasar2と同様の仕組みである。ただ細かく見ると,設計思想に違いがある。特徴が出るのは部品間の依存性の指定だ。

 一つは明示的に依存関係を記述する方法。DIの役割からすると,.diconファイルのような設定ファイルで明示的に指定するのが考えやすい。DIコンテナはこの情報を基にオブジェクト同士を結びつける。部品間の関係が明確になるというメリットもある。

 ただこの方法では,アプリケーション開発者の手間が増える。アプリケーションが複雑になるにつれ,すべての情報を記述しておくのは煩雑になる。逐一関係を指定するなら,部品にその依存性を記述するのとあまり変わらないという声もある。そこで,DIコンテナが自動的に結びつける部品を判断するというのがもう一つの方法である。

 前者を推奨しているのがSpringFrameworkだ。自動的に結びつける機能もあるが,開発者に対しても明示的に依存関係を記述するように推奨している。一方Seasar2は,後者を推奨する。「“易しく,優しく”がSeasar2の開発コンセプト。できる限り開発者の手間を省きたい」(Seasar2の生みの親である,電通国際情報サービス ビジネスソリューション事業部 プロダクトコンサルティング3部 マネージャーの比嘉康雄氏)という考え方に基づいているからだ。

 自動的に結びつける際に問題となるのは,対象となるオブジェクトが一意に決まらない場合があり得ること。前述のようにSeasar2では,実装するインタフェースによって結びつけるオブジェクトを識別している。同じインタフェースを実装したオブジェクトが複数ある場合,どちらを設定してよいのか分からない。

 そこでSeasar2では,階層的に部品を管理する仕組みを採り入れている(図4[拡大表示])。アプリケーションの構造によってコンテナをいくつかに分け,それぞれで部品を登録する。コンテナは親子関係にあり,全体として一つのツリーを構成している。各コンテナが関知するのは,自分自身と自分の子コンテナが管理している部品だけである。「このようにコンテナを分けることで,開発者が管理しやすくなるメリットもある」(比嘉氏)。ただこの方法でも,やはり重複が起こる可能性はある。重複した場合は,例外が発生する。

EJBに対する不満から生まれた

 DIの考え方に基づくコンテナはJava以外にも複数開発されている。例えば .NETプラットフォーム向けの「Spring .NET」や,Rubyを対象にした「Rico」などがある。ただ現時点では,実装は圧倒的にJavaのものが多い。DIの考え方がJava開発者の間で特に支持されているのは,J2EEによる開発に対する不満があるからだ。

 J2EEでは,EJB(Enterprise JavaBeans)というコンポーネント規約に基づいて部品を開発する。EJBの規約は,大規模な企業システムにも適用することを念頭に作られており,多人数で作業を分担させやすい半面,開発作業が複雑。実装も大掛かりになりがちだ。比較的小規模なアプリケーションの開発者はEJBを避ける傾向にある。

 またEJBは,EJBコンテナが提供するクラスを継承して作る必要がある。EJBコンテナがEJBを制御できるようにするためだ。だがこれではEJBにコンテナに依存するコードが入り込み,独立性の高い部品を作れない。

 テスト作業の負荷が高いのも,開発者にとってはありがたくない。EJBを動作させるためのミドルウェアであるEJBコンテナは概して,トランザクション管理,データの永続化など豊富な機能を備えた重い作りになっている。EJBを動かすためにはこの重いコンテナを毎回起動する必要がある。ちょっとした動作確認をしたい場合にも,多くの時間や手間がかかってしまう。

 DIコンテナを使えば,「開発作業がシンプルになり,テストをしやすい」(比嘉氏)というメリットが得られる。これまではEJBコンテナが部品の制御をしていたが,依存性の注入によってDIコンテナが部品を制御することになる。その結果,部品はシンプルなJavaオブジェクト(POJO:Plain Old Java Object)になる。部品間の結びつけをDIコンテナが担当するので,オブジェクト自身はシンプルなものにできる。

EJB 3.0にDIの考え方を導入

 DIの考え方は,EJBの次版である3.0にも導入される予定である。DIはそもそもEJBに対するアンチテーゼとして生まれた技術だが,EJBの次版はこれを取り込む決断をした。「批判には,時に有効な提案も含まれている。次に生かそうと考えた」(EJB 3.0の仕様策定責任者である米Sun Microsystems社のLinda DeMichiel氏)。

 EJB 3.0では,アノテーションという仕組みを利用してDIの情報を定義する(リスト[拡大表示])。アノテーションとは,簡単なキーワードを指定することでクラスに属性を与える仕組みである。例えばデータベースのデータソースを指定するために「@Resource」というキーワードを使う。他のクラスを設定する際は,「@Inject」というキーワードを用いる。

 DeMichiel氏によれば,EJB 3.0の最大のポイントは,仕様をシンプルにすることであるという。このため「機能を追加することよりも,複雑さを軽減することに力を入れた。DIの導入もその一つ。そのために,オープンソースのコミュニティなどさまざまな人と議論をし,よりよい仕様を策定するように努力した」(DeMichiel氏)。