岩永 大樹(いわなが ひろき)

 株式会社DTS ネットワーク事業本部所属。Struts/Springベースのフレームワークの研究開発を中心に業務を行っている。また,フレームワークの利用や開発プロセスに関する講師も行っている。

木村 真幸(きむら まさゆき)

 株式会社DTS ネットワーク事業本部 プロジェクトマネージャ。Javaを中心にフレームワーク開発や開発プロセス定義など幅広く活躍中。StrutsIDEコミッタ。著書「まるごとEclipse! Vol.1」(発行:インプレスコミュニケーションズ)。

 今回は,米GoogleがJavaで開発したDI(Dependency Injection)フレームワーク「Guice(ジュース)」を取り上げます。単体で使用することはもちろん,Webアプリケーションに組み込む方法や,Spring FrameworkやDWRとの連携も解説します。

XML定義ってうれしいですか?

 Springをはじめとするフレームワークにより,DIコンテナを使用して開発を行うことが一般的になってきました。しかし,beanを作成する際に,XMLファイルに定義するフルパッケージ名は「jp.co.nikkeibp.itpro.guice.spring.HelloServiceImpl」といった具合に長いことが多いです。

 図1のXMLファイルでは,上記のHelloServiceImplのbean定義を定義しています。しかし,この定義には間違っているところがあります。どこが間違っているか一目でわかるでしょうか?

図1●クラスの名のフルパッケージ名指定(間違いあり)
図1●クラスの名のフルパッケージ名指定(間違いあり)
[画像のクリックで拡大表示]

 図1の例では「HelloServiceImpl」のImplがimpl(Iが小文字)になっています。しかし,この状態でもアプリケーションを始動することは可能です。

 そして始動後,図2のように表示された例外情報を解析して,はじめて作成したアプリケーションにエラーがあることに気づくことになります。経験豊かな技術者であれば,すぐに例外の原因(この場合は記述ミス)を特定できますが,そうでない技術者にとっては解析作業は困難な作業と言えるでしょう。

図2●beanの名前が間違っているために出力された例外のスタックトレース
図2●beanの名前が間違っているために出力された例外のスタックトレース
[画像のクリックで拡大表示]

 すぐに解析できたとしても,指定したクラスを参照するには,自分で探してソースを開かなければなりません。大規模なアプリケーション開発では,以下のような理由でさらに記述ミスなどが増加します。

  • beanの定義が数え切れないほど多くなり,その定義の記述は膨大になる
  • 他のフレームワークと連携すると,XMLファイルをそれぞれ定義する必要がある
  • Webアプリケーション作成時には,web.xmlなどサーバーの設定に関するXMLファイルを扱う必要がある

 XMLファイルが増えてくると,どこに何が書いてあるのかわからなくなりがちです。DIコンテナを使用することで開発のコストを下げようとしているのにもかかわらず,その管理にコストがかかり,開発者に多大なストレスも与えます。DIのメリットを生かしつつ,XMLファイルのデメリットをなくす手段はないものでしょうか?

 その一つの答えがDIフレームワーク「Guice」なのです。

Guiceの特徴

 Guiceは,表1のような特徴を持っています。それぞれについて,簡単に説明しましょう。

表1●Guiceの特徴
特徴 概要
JavaでDI機能を使用可能 Javaを使用してDIの設定を行える
インジェクションの設定が容易 アノテーションを使用することでインジェクションの対象を決められる
スコープの設定が容易 アノテーションを使用することでスコープの設定ができる
単体テストが容易 Javaで実装されているため,JUnitなどで容易に単体テストができる
実績 Google最大のアプリケーションであるAdWordsにも使用されている

◆JavaでDI機能を使用可能

 DIのメリットとして,

  • 分業開発がしやすくなる
  • 他のクラスへの影響が少なくなり,メンテナンスが容易
  • モック・オブジェクトを使用することで,単体試験がやりやすい
があります。Guiceでは,JavaでDIの設定を記述するため,このメリットを損なうことなく,さらに以下のメリットを得ることができます。

  • クラス名などが間違っている場合,コンパイル・エラーが発生するので実行前に間違いがわかる
  • クラスを指定する際に,自動補完機能が使用可能なので,クラスの名前さえ覚えていれば入力が可能

◆インジェクションの設定が容易

 Guiceでは,アノテーションを利用してインジェクションを行います。インジェクションを行うメソッドやコンストラクタに「@Inject」を付けることで,インジェクションの対象を決定します。そのため,一般的なDIコンテナで行うインジェクションの様にsetterメソッドを特別扱いすることなく,好きなメソッドをインジェクションに使用するメソッドとすることができます(詳しい記述方法は後述)。

 また,インジェクションする対象のオブジェクトを指定しなくても暗黙的なインジェクションが可能であり,設定を簡略化することができます。

◆スコープの設定が容易

 クラスのGuice上でのスコープを決定する際にもアノテーションを使用できます。クラスをシングルトンで使用する場合,リスト1のように,クラスに「@Singleton」を付けることで指定します。


@Singleton
class MySingleton {
  ...
}
リスト1●アノテーションでのシングルトンの設定例

 ちなみに,シングルトンの設定にアノテーションを使用せず設定する場合は,モジュールにてリスト2のように設定します。


bind(MySingleton.class).in(Scopes.SINGLETON);
リスト2●バインディング時のシングルトン設定

 Singletonのイメージを図にすると図3のようになります。

図3●Singletonのイメージ
図3●Singletonのイメージ

 シングルトンの場合には,DIコンテナから最初にオブジェクトを取得するときにオブジェクトを作成します。しかし,リスト3のように設定することで,アプリケーションの起動時にオブジェクトを作成するように設定することも可能です。


bind(MySingleton.class).asEagerSingleton();
リスト3●バインディング時の設定(アプリケーション起動時にオブジェクト作成)

 EagerSingletonのイメージを図にすると図4のようになります。Singletonの場合に比べて,1度目のgetInstanceメソッドが呼ばれる前の時点ですでにオブジェクトが作成されています。

図4●EagerSingletonのイメージ
図4●EagerSingletonのイメージ

◆単体テストが容易

 SpringなどのDIコンテナにも言える共通の特徴でもありますが,オブジェクト間の依存性が排除できるため,JUnitを始めとした単体試験ツールを使用して簡単に試験を行うことができます。

 さらにGuiceでは依存関係などもJavaで記述するため,設定についてもJUnitなどによる単体試験を行うことが可能です。

◆実績

 まだバージョン1.0が完成して日が浅いものの,Guiceは,Google最大のアプリケーションであるAdWordsでも使用されています。

 ちなみにAdWordsは,Googleで検索した際に単語に関連する広告が出力されるサービスです(図5)。興味がある方は,上記AdWordsのサイトを参照してください。

図5●Google AdWordsは,検索結果の横に表示される広告サービス
図5●Google AdWordsは,検索結果の横に表示される広告サービス
[画像のクリックで拡大表示]