SpringFrameworkやSeaser2が流行したおかげで
近年、DIコンテナ(Dependency Injection コンテナ)が普及してきました。
DIコンテナは、オブジェクトの生成と組み立てを管理するフレームワークで、
これを使うことによって疎結合やAOPによる機能の折込など、さまざまなメリットが得られます。
この記事で紹介する、GuiceはGoogleで開発されたDIコンテナです。
Apache License 2.0で公開されており、無償で利用することができます。
http://code.google.com/p/google-guice/
主な特徴は、次の3点です。
・シンプル
・XML不要
・タイプセーフ
では簡単なサンプルを使ってGuiceを体験してみましょう。
このサンプルでは、アプリケーションのドメインモデルとして以下のオブジェクトを利用します。
・Service クラス
・Dependency インターフェイス
・DependencyImpl クラス
Serviceクラスは、属性としてDependency型のフィールドを持っています。
このフィールドに、Setterを介してDependencyImplクラスのオブジェクトをセットします。
このサンプルでは、上記のオブジェクトの組み立て処理(Dependency Injection)をGuiceを用いて実行してみましょう。
まずサービスクラスの実装は以下です。これはシンプルなオブジェクト(POJO)です。
Service.java
package net.kronos_jp.guice;
import com.google.inject.Inject;
public class Service{
private Dependency depend;
public Dependency getDependency() {
return depend;
}
@Inject
public void setDependency(Dependency value) {
this.depend = value;
}
}
@Injectアノテーションを使って依存するオブジェクトインスタンスを設定する場所を指定しています。
この@InjectアノテーションはSetterのみならず、Dependency型を持つフィールドやDependency型の引数を受け取るコンストラクタにも指定することが出来ます。
次は、DependencyインターフェイスとDependencyImplクラスです。
これらもすべてシンプルなJavaオブジェクトです。
Dependency.java
package net.kronos_jp.guice;
public interface Dependency {
public void execute();
}
DependencyImpl.java
package net.kronos_jp.guice;
public class DependencyImpl implements Dependency{
public void execute() {
System.out.println("Hello World");
}
}
Spring Frameworkなど他のDIコンテナでは、XMLファイルでインジェクションの設定を記述しますが、GuiceではJavaのコードでインジェクションの設定を記述します。
Guiceでインジェクションを設定するには、以下のようにJavaコードを記述します。
MyModule.java
package net.kronos_jp.guice;
import com.google.inject.AbstractModule;
public class MyModule extends AbstractModule {
protected void configure() {
this.bind(Dependency.class).to(DependencyImpl.class);
}
}
Guiceでは設定のために、AbstractModule抽象クラスを継承したクラスを作成します。
(正確には、Moduleインターフェイスを実装したクラスを作成します。)
このクラスのことをModuleと呼びます。
Moduleクラスでは、コールバックメソッドであるconfigure()メソッドをオーバーライドします。
configure()メソッドの中で、初めに利用するのはbind()メソッドです。 <このメソッドは、親クラス(AbstractModuleクラス)が提供しています。 BR>
bind()メソッドに、インジェクトの受け口として設定したインターフェイスまたはクラスのClass型を引数として渡し、インジェクトの受け口を検索します。
次に、このbind()メソッドの戻り値である、Binder型オブジェクトのto()メソッドを使って、インターフェイスの実装クラスを記述します。
以上で、DIの設定は終了です。
こうして、出来上がったModuleクラスのインスタンスをGuiceクラスのcreateInjector()スタティックメソッドに渡してやると、
戻り値としてInjectorインターフェイスオブジェクトが取得できます。このInjectorのgetInstance()メソッドでインスタンスを取得します。
サンプルアプリケーションでは、この処理をJavaの起動メソッドで呼び出すことにします。
Main.java
package net.kronos_jp.guice;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Main {
public static void main(String args[]){
MyModule mod = new MyModule();
Injector i = Guice.createInjector(mod);
Service var = i.getInstance(Service.class);
var.getDependency().execute();
}
}
ためしに、インターフェイスを実装してないクラスをインジェクトしようとしたら、コンパイルエラーになりました。
XMLに定義するスタイルのDIコンテナだと、このエラーをコンパイル時に発見することはできません。
この仕組みはJDK5のGenericsのお手本のような使い方だといえるでしょう。
|