状況:いくつかのFooClass
で遅延依存関係のインスタンス化が必要なため、コンストラクターパラメーターとしてInjector
をクラスに渡します。
private final Injector m_injector;
public FooClass(@Named("FooInjector") Injector injector) {
m_injector = injector;
}
しかし、guiceはコアクラス(インジェクター、モジュールなど)をバインドすることを許可していません。解決策は何ですか?
Injector
を直接使用しないでください。代わりにProvider<FooClass>
を渡します。また、FooClass
を使用する場所にプロバイダーを注入する必要があります。
private final Provider<FooClass> provider;
@Inject
public ClassWhereFooIsUsed(Provider<FooClass> provider) {
this.provider = provider;
}
.... somewhere else
FooClass f = provider.get(); // This is lazy
他の人がすでに答えているように、Guiceがバインディング自体を定義しているので、単に_@Inject Injector
_を使用できます。
通常、アプリに必要なInjector
は1つだけです。静的変数は、シングルトンを挿入するよりも簡単に保存してアクセスする方法です。私たちのWebアプリでは、 stripes-guicer を使用し、必要なときに静的メソッドGuiceInjectorFactory.getInjector()
からInjector
を取得します(たとえば、Hibernateインターセプターで) 。
「インジェクターを直接使うべきではない」というアドバイスに少し戸惑っています。 injector.getInstance()
またはinjector.injectMembers()
を呼び出す以外に、他にどのようにインスタンスを注入できますか?道はない。はい、プロバイダーメソッドを定義できますが、どこかで何かがインジェクターを使用しない限り、それらが呼び出されることはありません。はい、 ServletModule ;のようにInjector
を使用するモジュールがあります。 Injector
を自分で作成する必要がありますが、その後はServletModule
に任せることができます。
したがって、状況によっては、Injector
を直接使用することを避けることができますが、それは「使用すべきではない」という意味ではありません。オプションのモジュールなしでGuiceを単独で使用している場合は、インジェクションをトリガーする他の方法がないため、あらゆる場所でInjector
を使用する必要があります。 (フレームワーク内でコードを書くのに一日を費やす開発者は、実際に自分のオブジェクトをインスタンス化する人がいることを忘れることがあると思います。)
@gpamparaが言ったように、Provider<T>
は遅延/オプションの初期化に使用する必要があります。また、他の質問への回答で述べたように、ほとんどの場合、コード内のInjector
への参照は避ける必要があります。
とは言うものの、Guiceによって作成されたクラスでは、オブジェクトを作成しているInjector
は、Injector
への依存関係を宣言するだけで注入できます。 Injector
は、バインディングを宣言しなくても、自動的にインジェクションに使用できます。
Injector
を注入する場合は、なぜそれを実行するのかを考える必要があります。クラスが依存する実際のインターフェース/クラスへの依存関係を宣言してみませんか?コンストラクターに新しい依存関係を追加するのは、コードの他の場所でInjector
を介して依存関係のインスタンスを取得するのと同じくらい簡単であり、コードをはるかに理解しやすくします。
おそらくがInjector
のインスタンスを挿入するべきではないという引数は非常に有効ですが、他のルールと同様に例外があります。
インスタンスを提供する必要のあるクラス参照を取り込むファクトリクラスがあります。インスタンスは必ずしもわかっているわけではないので(実際にはわかっていますが、たくさんあり、もっとあるかもしれません)、すべてのインスタンスのプロバイダーを作成することはできません。
public class ThingFactory {
private Injector injector;
@Inject
ThingFactory(Injector injector) {
this.injector = injector;
}
public <T> T getInstance(Class<T> aClass) {
return injector.getInstance(aClass);
}
}
私のアプリの実際のクラスは、別のクラスを拡張してオーバーライドしています。そのため、このクラスは基本的にGuiceへのパススルーです。