web-dev-qa-db-ja.com

インジェクターを注入する方法は?

状況:いくつかのFooClassで遅延依存関係のインスタンス化が必要なため、コンストラクターパラメーターとしてInjectorをクラスに渡します。

private final Injector m_injector;

public FooClass(@Named("FooInjector") Injector injector) {
m_injector = injector;
}

しかし、guiceはコアクラス(インジェクター、モジュールなど)をバインドすることを許可していません。解決策は何ですか?

29
Alex M

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
28
gpampara

他の人がすでに答えているように、Guiceがバインディング自体を定義しているので、単に_@Inject Injector_を使用できます。

通常、アプリに必要なInjectorは1つだけです。静的変数は、シングルトンを挿入するよりも簡単に保存してアクセスする方法です。私たちのWebアプリでは、 stripes-guicer を使用し、必要なときに静的メソッドGuiceInjectorFactory.getInjector()からInjectorを取得します(たとえば、Hibernateインターセプターで) 。

「インジェクターを直接使うべきではない」というアドバイスに少し戸惑っています。 injector.getInstance()またはinjector.injectMembers()を呼び出す以外に、他にどのようにインスタンスを注入できますか?道はない。はい、プロバイダーメソッドを定義できますが、どこかで何かがインジェクターを使用しない限り、それらが呼び出されることはありません。はい、 ServletModule ;のようにInjectorを使用するモジュールがあります。 Injectorを自分で作成する必要がありますが、その後はServletModuleに任せることができます。

したがって、状況によっては、Injectorを直接使用することを避けることができますが、それは「使用すべきではない」という意味ではありません。オプションのモジュールなしでGuiceを単独で使用している場合は、インジェクションをトリガーする他の方法がないため、あらゆる場所でInjectorを使用する必要があります。 (フレームワーク内でコードを書くのに一日を費やす開発者は、実際に自分のオブジェクトをインスタンス化する人がいることを忘れることがあると思います。)

12
David Noha

@gpamparaが言ったように、Provider<T>は遅延/オプションの初期化に使用する必要があります。また、他の質問への回答で述べたように、ほとんどの場合、コード内のInjectorへの参照は避ける必要があります。

とは言うものの、Guiceによって作成されたクラスでは、オブジェクトを作成しているInjectorは、Injectorへの依存関係を宣言するだけで注入できます。 Injectorは、バインディングを宣言しなくても、自動的にインジェクションに使用できます。

Injectorを注入する場合は、なぜそれを実行するのかを考える必要があります。クラスが依存する実際のインターフェース/クラスへの依存関係を宣言してみませんか?コンストラクターに新しい依存関係を追加するのは、コードの他の場所でInjectorを介して依存関係のインスタンスを取得するのと同じくらい簡単であり、コードをはるかに理解しやすくします。

8
ColinD

おそらく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へのパススルーです。

2
Drew Stephens