前編では、Guiceの概要と導入、そしてGuiceによるDIの設定からインスタンスの生成と実行までの一連の流れについて解説しました。後編ではDIの設定における応用テクニックについて解説します。
応用編
応用編では、DIの設定について3つの方法を紹介します。そして最後にサーブレット(Webアプリケーション)で利用する方法を紹介します。
DIの設定
方法その1-依存性をアノテーションで指定する
GuiceによるDIの設定は、前編で紹介したもの以外にもいくつかの方法が用意されています。ここでは、注入する具象クラスをアノテーションで指定する方法を紹介します。これにより、ソースコードの記述をよりシンプルにすることができます。
具体的には、インターフェースに対応する注入される具象クラスを、アノテーション@ImplementedByで指定します(リスト5)。これでモジュールの作成が不要になると共に、Injectorを生成するcreateInjector()メソッドの引数も不要になります。
方法その2-注入の対象に名前をつける
依存性を注入する対象が複数存在するときには、それぞれに名前がつけてあると便利です。名前はアノテーション@Namedでリスト6のようにつけます。ここではプリミティブ型(int)の変数に名前をつけていますが、一般のオブジェクトであっても同じです。
@Namedによって名前をつけられた対象に依存性を注入する場合は、リスト7のようにannotatedWith()とnamed()の両メソッドを使います。named()はcom.google.inject.name.Namesクラスのメソッドですが、このクラスの静的(static)インポートによって、メソッド名だけの記述にしています。
方法その3 - Providerによるインスタンスの生成
先ほどまでの例では、new演算子でインスタンスを生成するのとあまり変わりがないと思うかもしれません。しかしGuiceでは、インスタンスの生成時により複雑な処理を行うこともできます。それを担うのがProviderです。
たとえば通販サイトを想定して、注文明細データを持つCartインスタンスを内包したOrderインスタンスを生成するとします。このとき、Injectorを使ってこのインスタンスを生成するにはどうしたらよいでしょうか。ただしOrderとCartは同じインターフェースを持っていないとします。こうしたときProviderを使うのが有効です。
先にInjectorとモジュールを見てみましょう(リスト8)。toProvider()メソッドと、OrderProviderクラスが新たに現れました。このクラスはすぐあとで作成しますが、Orderインスタンスを生成する処理が記述されています。
OrderProviderクラスはリスト9のように作成しました。インスタンスの生成はget()メソッドで行われます。このメソッドの戻り値の型とProvider<Order>における<Order>の部分とが同じでなければなりません。この部分は<T>のようにテンプレート型で表すこともできます。その場合はget()メソッドの戻り値もT型として宣言します。
リスト9ではCartのコンストラクタに付与されたIDが引数で渡されますが、このIDはInjectorによりOrderインスタンスが生成されるたびに1ずつ増えるようになっています。つまり注文が入るたびに付与されるIDが増えていくということになります。本来の業務アプリケーションであれば、IDはデータベースなどで生成されたものを使うことになるでしょう。
サーブレット(Webアプリケーション)での利用
執筆時点では、Guiceのドキュメントにあまり詳しくは記述されていませんが、実はサーブレットでGuiceを利用する方法も用意されています。その際、前提としてサーブレットがデプロイされるコンテキストで、サーブレットフィルタGuiceFilterが有効になっていなくてはなりません。
有効にするには、GuiceのJARファイルをコンテキストの/WEB-INF/libフォルダにデプロイした上で、同コンテキストのweb.xmlにリスト10の内容を追加します。追加する位置についてはweb.xmlの仕様を参照してください。
サーブレットでGuiceを利用すると、以下のようにInjectorからリクエスト(HttpServletRequest)やセッション(HttpSession)のインスタンスが取得できるようになります。
このため、サーブレットで利用される業務クラスが、リクエストやセッションを引数として宣言する必要がなくなります。こうするとサーブレットと業務クラスとの依存度を少なくなり、業務クラス単体でのテストがやりやすくなります。
これを実現するには、InjectorでServletModuleを利用します(リスト11)。そしてInjectorを業務クラスで利用できるようにしておきます。他のDI設定が必要であれば、configure()メソッドで一緒に設定しておくとよいでしょう。
また、以下のように@RequestParametersをMap型の変数に付記すれば、業務クラスにリクエストパラメータを注入することもできますので、業務クラスをPOJO(Plain Old Java Object)として扱いやすくなります。
おわりに
Googleのエンジニアにより開発されたDIフレームワークGuiceについて紹介しましたが、いかがでしたでしょうか。スコープやSpring Frameworkとの連携など、取り上げることができなかった機能がまだまだ存在します。ぜひあなたもGuiceを最後の一滴まで飲み干してください。
なお、ここまで部分だけを紹介したサンプルの、全体のソースコードはGuice10Sample.zipです(web.xmlはTomcat6用)。実際に試してみると、Guiceの味がよくわかることでしょう。