web-dev-qa-db-ja.com

モジュールでGuiceインジェクターにアクセスしますか?

私はGuiceのAbstractModuleを拡張しており、拡張するクラスの内部でGuiceのインジェクターにアクセスする必要があります。それが可能な場合、可能であれば、どうやって?

33
stefan.at.wpf

これは珍しい要求です。モジュールは、ロジックファイルというよりも構成ファイルに似ています。モジュールは、インジェクターを作成するために読み取られ、インジェクターが作成されるとすぐに、モジュールがその役割を果たします。単純なモジュールの場合、インジェクターは、モジュールを破棄する準備ができるまで文字通り存在しません。

いずれにせよ、クラスXを取得するためにインジェクターを要求するのではなく、通常は_Provider<X>_を要求する必要があります。 Guiceは X、_Provider<X>_、または_Provider<X>_ のバインディングにXまたは_@Provides X_を挿入します。ほとんどの場合、代わりにこれを行います。そうは言っても、インジェクターをインジェクトすると、インスタンスを反射的に取得したり、インジェクターのバインディング(など)を検査したりできるようになります。

モジュール内からインジェクターにアクセスする必要があるいくつかの有効な理由/設計は次のとおりです。

_@Provides_メソッド内:

モジュールには、ミニプロバイダーを _@Provides_ で注釈されたメソッドに含めることができます。覚えておいてください Injector is injectable :これらのメソッドのいずれかにインジェクターが必要な場合は、パラメーターとして受け入れることができます。

_public class OneModule extends AbstractModule {
  @Override public void configure() { /* ... */ }

  @Provides YourDependency getYourDependency(Injector injector) {
    return injector.getInstance(Class.forName(yourDependencyName));
  }

  @Provides Something getSomething(SomethingImpl something) {
    return initialize(something); // preferred: only ask for what you need
  }

  @Provides SomethingElse getSomethingElse(Provider<Thing> thingProvider) {
    return new SomethingElse(thingProvider); // asking for a provider works too
  }
}
_

Configure()でプロバイダーを取得するには:

AbstractModulesは getProvider() を正確にこの理由で公開しますが、インジェクタが提供する準備ができる前にそのプロバイダでget()を呼び出すとエラーが発生します(構成時など):

_public class TwoModule extends AbstractModule {
  @Override public void configure() {
    bind(Thingy.class).toInstance(
        new MyThingy(8675309, getProvider(Another.class)));
  }
}
_

あなたはおそらくgetProvider(Injector.class)を呼び出すことができますが、それが機能するかどうかはわかりませんし、なぜあなたがしたいのかわかりません。

Configure()でインスタンスを取得するには:

これは悪い考えです。 Guiceは、すべての構成メソッドが実行されるまで、インスタンスを提供する準備ができていません。あなたが得ることができる最も近いものは 子インジェクターを作成する 他のモジュールを使用してこのモジュールに渡すことですが、それが必要になることはめったにありません。

_public class MainClass {
  public static void main(String[] args) {
    Injector firstStage =
        Guice.createInjector(new OtherModule1(), new OtherModule2());
    // An alternative design would @Inject-annotate fields in ThreeModule
    // and get it from firstStage, but that's nonstandard and may be confusing.
    Injector secondStage =
        firstStage.createChildInjector(new ThreeModule(firstStage));
  }
}

public class ThreeModule extends AbstractModule {
  private final Injector otherInjector;

  public ThreeModule(Injector otherInjector) { 
    this.otherInjector = otherInjector;
  }

  @Override public void configure() {
    bindStuffBasedOn(otherInjector);
  }
}
_
51
Jeff Bowman