Google Guiceガイド
1前書き
この記事では、
Google Guiceの基礎
について説明します。 Guiceで基本的な依存性注入(DI)タスクを完了するためのアプローチを見ていきます。
また、Guiceのアプローチと、Spring and Contexts and Dependency Injection(CDI)のようなより確立されたDIフレームワークのアプローチとを比較対照します。
この記事では、読者がリンクの基礎について理解していることを前提としています。
2セットアップ
MavenプロジェクトでGoogle Guiceを使用するには、
pom.xml
に次の依存関係を追加する必要があります。
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.1.0</version>
</dependency>
Guiceエクステンションのコレクションもあります(それらについては後で説明します)。https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.google.inject.extensions%22% 20AND%20v%3A%224.1.0%22[ここ]、およびhttps://github.com/google/guice/wiki/3rdPartyModules[サードパーティ製のモジュールとして]Guiceの機能を拡張する(主に統合を提供することによって)より確立されたJavaフレームワークへ)。
3 Guice
による基本的な依存性注入
3.1. 私たちのサンプルアプリケーション
電子メール、SMS、およびIMの3つのヘルプデスクビジネスのコミュニケーション手段をサポートするクラスを設計するシナリオを進めます。
クラスを考えてみましょう:
public class Communication {
@Inject
private Logger logger;
@Inject
private Communicator communicator;
public Communication(Boolean keepRecords) {
if (keepRecords) {
System.out.println("Message logging enabled");
}
}
public boolean sendMessage(String message) {
return communicator.sendMessage(message);
}
}
このCommunicationクラスは、通信の基本単位です。このクラスのインスタンスは、利用可能な通信チャネルを介してメッセージを送信するために使用されます。上記のように、
Communication
には
Communicator
があり、これを使って実際のメッセージ送信を行います。
Guiceへの基本的な入り口は__Injectorです。
public static void main(String[]args){
Injector injector = Guice.createInjector(new BasicModule());
Communication comms = injector.getInstance(Communication.class);
}
このメインメソッドは
Communication
クラスのインスタンスを取得します。また、Guiceの基本概念である
Module
(この例では
BasicModule
を使用)も紹介します。
Module
はバインディングの定義の基本単位
(またはSpringで知られているように配線)です。
-
Guiceは依存性の注入と管理のためにコード優先のアプローチを採用しています** ので、多くのXMLをそのまま使用することはできません。
上記の例では、
Communication
の依存関係ツリーは、クラスにデフォルトの引数なしのコンストラクタがある場合、
just-in-time binding
と呼ばれる機能を使用して暗黙的に挿入されます。これは、Guiceの開始当初からの機能であり、v4.3以降のSpringでのみ利用可能です。
3.2. Guiceのバインディング
結束はGuiceに対するもので、配線はSpringに対するものです。バインディングでは、Guiceが依存関係をクラスに注入する方法を定義します。
バインディングは、
com.google.inject.AbstractModule
の実装で定義されています。
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Communicator.class).to(DefaultCommunicatorImpl.class);
}
}
このモジュール実装は、
Communicator
変数が見つかった場合は常に
DefaultCommunicatorImpl
のインスタンスをインジェクトすることを指定します。
-
このメカニズムのもう一つの具体例は
named binding
** です。次の変数宣言を考えてください。
@Inject @Named("DefaultCommunicator")
Communicator communicator;
このために、次のようなバインディング定義があります。
@Override
protected void configure() {
bind(Communicator.class)
.annotatedWith(Names.named("DefaultCommunicator"))
.to(Communicator.class);
}
このバインディングは、
@ Named(“ DefaultCommunicator”)
アノテーションが付けられた変数に
Communicator
のインスタンスを提供します。
@ Inject
アノテーションと
@ Named
アノテーションは、JavaEEのCDIからのローンアノテーションのように見えますが、それらはそうです。これらは
com.google.inject。**
パッケージに含まれています – IDEを使用するときは、正しいパッケージからインポートするように注意する必要があります。
ヒント:
Guiceが提供する
@ Inject
と
@ Named
を使用すると述べたのですが、Guiceは
javax.inject.Inject
と__javax.inject.Namedをサポートしています。アノテーション
-
constructor binding
** を使用して、デフォルトの引数なしのコンストラクタがない依存関係を注入することもできます。
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Boolean.class).toInstance(true);
bind(Communication.class).toConstructor(
Communication.class.getConstructor(Boolean.TYPE));
}
上記のスニペットは、
boolean
引数を取るコンストラクタを使用して
Communication
のインスタンスを挿入します。
Boolean
クラスの
untargeted binding
** を定義することによって、コンストラクターに
true
引数を提供します。
この
untargeted binding
は
boolean
パラメータを受け付けるバインディング内のコンストラクタに熱心に提供されます。このアプローチでは、Communicationのすべての依存関係が注入されます。
-
コンストラクタ固有のバインディングへのもう1つのアプローチは
instance binding
** です。ここではバインディングにインスタンスを直接提供します。
public class BasicModule extends AbstractModule {
@Override
protected void configure() {
bind(Communication.class)
.toInstance(new Communication(true));
}
}
Communication
変数が宣言されている場合は常に、このバインディングは
Communication
クラスのインスタンスを提供します。
ただしこの場合、クラスの依存関係ツリーは自動的に配線されません。重い初期化や依存性注入が必要ない場合は、このモードの使用を制限してください。
4依存性注入の種類
Guiceは、DIパターンで予想されるような標準的な種類の注射をサポートしています。
Communicator
クラスでは、さまざまなタイプの
CommunicationMode
を注入する必要があります。
4.1. フィールドインジェクション
@Inject @Named("SMSComms")
CommunicationMode smsComms;
名前に基づいてターゲットインジェクションを実装するための修飾子としてオプションの
@ Named
アノテーションを使用する
4.2. メソッドインジェクション
ここでは、注入を達成するためにセッターメソッドを使用します。
@Inject
public void setEmailCommunicator(@Named("EmailComms") CommunicationMode emailComms) {
this.emailComms = emailComms;
}
4.3. コンストラクタインジェクション
コンストラクタを使って依存関係を注入することもできます。
@Inject
public Communication(@Named("IMComms") CommunicationMode imComms) {
this.imComms= imComms;
}
4.4. 暗黙のインジェクション
Guiceは、
Injector
や
java.util.Logger
のインスタンスなど、いくつかの汎用コンポーネントを暗黙的にインジェクトします。サンプル全体を通してロガーを使用していることに気付くでしょうが、実際のバインディングは見つからないでしょう。
5 Guiceでスコーピング
Guiceは、他のDIフレームワークでこれまで使用してきたスコープとスコープメカニズムをサポートしています。 Guiceはデフォルトで、定義された依存関係の新しいインスタンスを提供します。
5.1. シングルトン
アプリケーションにシングルトンを注入しましょう。
bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator"))
.to(Communicator.class).in(Scopes.SINGLETON);
in(Scopes.SINGLETON)
は、
@ Named(“ AnotherCommunicator”)
を持つ
Communicator
フィールドにシングルトンが挿入されることを指定します。このシングルトンはデフォルトで遅延開始されます。
5.2. 熱心なシングルトン
さて、熱心なシングルトンを注入しましょう:
bind(Communicator.class).annotatedWith(Names.named("AnotherCommunicator"))
.to(Communicator.class)
.asEagerSingleton();
asEagerSingleton()
呼び出しは、シングルトンを熱心にインスタンス化されたものとして定義します。
これら2つのスコープに加えて、Guiceはカスタムスコープと、JavaEEによって提供されるWebのみの
@ RequestScoped
および
@ SessionScoped
アノテーションをサポートします(これらのアノテーションのGuice提供バージョンはありません)。
6. Guiceでのアスペクト指向プログラミング
Guiceは、AOPAllianceのアスペクト指向プログラミングの仕様に準拠しています。この例では、4つのステップでメッセージ送信の追跡に使用する典型的なロギングインターセプターを実装できます。
ステップ1 – AOPAllianceの
MethodInterceptor
を実装する
:
public class LoggingInterceptor implements MethodInterceptor {
@Inject
Logger logger;
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[]objectArray = invocation.getArguments();
int i = 0;
for (Object object : objectArray) {
logger.info("Sending message: " + object.toString());
}
return invocation.proceed();
}
}
ステップ2 – プレーンなJavaアノテーション
を定義します.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MessageSentLoggable {
}
ステップ3 –
Matcher
:
のバインディングを定義する
Matcher
は、AOPアノテーションが適用されるコンポーネントを指定するために使用するGuiceクラスです。この場合、注釈を__CommunicationModeの実装に適用する必要があります。
public class AOPModule extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(MessageSentLoggable.class),
new MessageLogger()
);
}
}
ここでは、
MessageLogger
インターセプターを
any
クラスに適用する
Matcher
を指定しています。これには、そのメソッドに
MessageSentLoggable
アノテーションが適用されています。
ステップ4 – アノテーションを
CommunicationMode
に適用してモジュールをロードします
@Override
@MessageSentLoggable
public boolean sendMessage(String message) {
logger.info("SMS message sent");
return true;
}
public static void main(String[]args) {
Injector injector = Guice.createInjector(new BasicModule(), new AOPModule());
Communication comms = injector.getInstance(Communication.class);
}
7. 結論
Guiceの基本的な機能を見てきたところで、Guiceのインスピレーションが春から来たところを見ることができます。
JSR-330
のサポートとともに、Guiceはインジェクション重視のDIフレームワークを目指しています(Springは、プログラミングの利便性のためにエコシステム全体を提供するのに対して必ずしもDIだけではありません)、DIの柔軟性を求める開発者を対象としています。
Guiceはまた非常に拡張性があります
、プログラマがフレームワークの柔軟で創造的な使用をもたらすポータブルプラグインを書くことを可能にします。これは、Guiceがサーブレット、JSF、JPA、およびOSGiなどの最も一般的なフレームワークおよびプラットフォーム用にすでに提供している広範な統合に加えています。
このチュートリアルで使用されているすべてのソースコードは、https://github.com/eugenp/tutorials/tree/master/guice[GitHubプロジェクト]にあります。