Google Guiceの依存性注入の例に関するチュートリアル
Google Guiceは、アプリケーションの依存関係の自動化を行うフレームワークです。もし直接ここに来たのであれば、従来のオブジェクトの作成方法の問題と依存性インジェクションの実装の利点を学んだ依存性インジェクションの例をチェックすることをおすすめします。前のチュートリアルでは、アプリケーションでの依存性インジェクションを手動で実装する方法を学びました。しかし、クラスの数が増えると、このタスクを自動化するためのフレームワークを探す方が良いです。Google Guiceは、依存性インジェクションの自動実装を提供する主要なフレームワークの一つです。前の投稿から同じ例を使って、Google Guiceを使用して依存性インジェクションの実装プロセスを自動化する方法を学びましょう。Google Guiceの依存関係は、Maven Centralで利用できるので、Mavenプロジェクトでは以下の依存関係を追加することができます。
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
もしシンプルなJavaアプリケーションをお持ちの場合、Google Guiceのホームページからjarファイルをダウンロードすることができます。ただし、この場合はトランジティブな依存関係もクラスパスに含める必要があります。そうでないとランタイムエラーが発生します。例として、以下の画像のようなプロジェクト構造を持つMavenプロジェクトがあります。それでは、各コンポーネントを一つずつ見ていきましょう。
サービスクラス
package com.scdev.di.services;
public interface MessageService {
boolean sendMessage(String msg, String receipient);
}
MessageServiceインターフェースは、サービスの基本契約を提供します。
package com.scdev.di.services;
import javax.inject.Singleton;
//import com.google.inject.Singleton;
@Singleton
public class EmailService implements MessageService {
public boolean sendMessage(String msg, String receipient) {
//some fancy code to send email
System.out.println("Email Message sent to "+receipient+" with message="+msg);
return true;
}
}
EmailServiceはMessageServiceの実装の1つです。このクラスは@Singletonアノテーションで注釈付けされていることに注意してください。サービスオブジェクトはインジェクタクラスを介して作成されるため、このアノテーションはサービスクラスがシングルトンオブジェクトであることを知らせるために提供されています。Google Guice 3.0ではJSR-330のサポートが追加され、com.google.injectまたはjavax.injectパッケージのアノテーションを使用することができます。例えば、Facebookメッセージを送信する別のサービスの実装があるとしましょう。
package com.scdev.di.services;
import javax.inject.Singleton;
//import com.google.inject.Singleton;
@Singleton
public class FacebookService implements MessageService {
public boolean sendMessage(String msg, String receipient) {
//some complex code to send Facebook message
System.out.println("Message sent to Facebook user "+receipient+" with message="+msg);
return true;
}
}
消費者クラス (Shōhisha kurasu)
私たちはアプリケーションで依存性注入を実装しているので、サービスクラスはアプリケーション内では初期化されません。Google Guiceは、セッターベースとコンストラクタベースの両方の依存性注入をサポートしています。サービスを使用する私たちのアプリケーションクラスは以下のようになります。
package com.scdev.di.consumer;
import javax.inject.Inject;
//import com.google.inject.Inject;
import com.scdev.di.services.MessageService;
public class MyApplication {
private MessageService service;
// constructor based injector
// @Inject
// public MyApplication(MessageService svc){
// this.service=svc;
// }
//setter method injector
@Inject
public void setService(MessageService svc){
this.service=svc;
}
public boolean sendMessage(String msg, String rec){
//some business logic here
return service.sendMessage(msg, rec);
}
}
コンストラクタベースのインジェクションのためにコードにコメントを追加しました。これは、アプリケーションがサービスクラスオブジェクトを必要としない他の機能も提供する場合に便利です。また、@Injectorアノテーションにも注意してください。これは、Google Guiceによってサービス実装クラスにインジェクトされるために使用されます。アノテーションについて詳しく知りたい場合は、Javaアノテーションのチュートリアルをご覧ください。
バインディングサービスの実装
明らかにGoogle Guiceはどのサービスを使用するかわからないため、AbstractModule抽象クラスを拡張して、configure()メソッドの実装を提供する必要があります。
package com.scdev.di.injector;
import com.google.inject.AbstractModule;
import com.scdev.di.services.EmailService;
import com.scdev.di.services.FacebookService;
import com.scdev.di.services.MessageService;
public class AppInjector extends AbstractModule {
@Override
protected void configure() {
//bind the service to implementation class
//bind(MessageService.class).to(EmailService.class);
//bind MessageService to Facebook Message implementation
bind(MessageService.class).to(FacebookService.class);
}
}
実装のどれをサービスクラスにバインドするかは自由です。例えば、EmailServiceに切り替えたい場合は、バインドの変更だけで済みます。
クライアントアプリケーション
私たちのセットアップは準備ができていますので、シンプルなJavaクラスを使い方を見てみましょう。
package com.scdev.di.test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.scdev.di.consumer.MyApplication;
import com.scdev.di.injector.AppInjector;
public class ClientApplication {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppInjector());
MyApplication app = injector.getInstance(MyApplication.class);
app.sendMessage("Hi Pankaj", "scdev@abc.com");
}
}
実装は非常に理解しやすいです。GuiceクラスのcreateInjector()メソッドを使用してInjectorオブジェクトを作成する必要があります。その際に、インジェクタークラスの実装オブジェクトを渡します。その後、インジェクターを使用してコンシューマークラスを初期化します。上記のクラスを実行すると、以下の出力が生成されます。
Message sent to Facebook user scdev@abc.com with message=Hi Pankaj
もしAppInjectorクラスのEmailServiceのバインディングを変更すれば、以下の出力が生成されます。
Email Message sent to scdev@abc.com with message=Hi Pankaj
JUnitのテストケース
私たちは、MyApplicationクラスをテストしたいため、実際のサービス実装を作成する必要はありません。以下のようなシンプルなモックサービス実装クラスを利用することができます。
package com.scdev.di.services;
public class MockMessageService implements MessageService{
public boolean sendMessage(String msg, String receipient) {
return true;
}
}
私のJUnit 4のテストクラスは以下のようになっています。
package com.scdev.di.test;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.scdev.di.consumer.MyApplication;
import com.scdev.di.services.MessageService;
import com.scdev.di.services.MockMessageService;
public class MyApplicationTest {
private Injector injector;
@Before
public void setUp() throws Exception {
injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(MessageService.class).to(MockMessageService.class);
}
});
}
@After
public void tearDown() throws Exception {
injector = null;
}
@Test
public void test() {
MyApplication appTest = injector.getInstance(MyApplication.class);
Assert.assertEquals(true, appTest.sendMessage("Hi Pankaj", "scdev@abc.com"));;
}
}
テストメソッドの前に実行されるsetUp()メソッド内で、AbstractModuleの匿名クラス実装によって、MockMessageServiceクラスをMessageServiceにバインドしていることに注意してください。
Google Guice プロジェクトをダウンロードしてください。
Google Guiceの例のチュートリアルは以上です。アプリケーションの依存性注入を実装するためのGoogle Guiceの使用は非常に簡単で、美しく実現できます。GoogleのAPIで使用されているため、高いテストが行われ信頼性のあるコードです。上記からプロジェクトをダウンロードして、もっと学ぶために試してみてください。