9

インスタンスを名前付きアノテーションに動的にバインドするモジュールを作成したいと思います。ユースケースは、@Named 値であるプロパティ ファイルのキーを使用して、構成の値を自動的にバインドすることです。

ただし、構成は別のモジュールにバインドされているため、構成を注入する必要があります。私が見た解決策は次のとおりです。

  1. configure() メソッドでのバインディング。このメソッドは注入されず、基本構成を取得できません。

  2. Provider/@Provides の使用。プロバイダーは単一のインスタンスのみをバインドします。

  3. マルチバインダーを使用。私の使用例は、この拡張機能によって提供されるものとは少し異なります。マルチバインディングを使用すると、複数のインスタンスを個別にバインドし、より複雑な包含型の Collection としてそれらを注入できます。各インスタンスを個別にバインドし、後で注入するために一意に識別できるようにしたいと思います。

  4. childInjector を使用します。残念ながら、既存のコードを大幅に変更しない限り、これは不可能です。この回答は、この問題をこの方法で解決する方法の非常に良い説明です。

  5. 何とかバインダーを注入。(少しハッカーになり始めました) Guice では、後で使用するためにインジェクターを注入できます。 @Provides メソッドを介してバインダーをモジュールに注入し、バインダーを直接使用してメソッド内で複数のバインドを作成してみました。Guice はバインダーを注入しません。

4

1 に答える 1

9

インジェクションが発生する前に、すべてconfigureメソッドがすべてのバインディングを構成することに注意してください。とはいえ、いくつかのこと:Injector

  1. プロパティを 1 つのインスタンス@Namedのコンテンツにバインドすることは非常に便利です。これを自動的に行うメソッドがあります。唯一の秘訣は、実行時にインスタンスが必要なことです。PropertiesNames.bindProperties(...)Propertiesconfigure()

    それらがすべて同時に使用できる場合は、あるモジュールでプロパティをバインドし、別のモジュールでアプリケーションをバインドすることについて心配する必要はありません。それらがすべて同じ に入る限りInjector、Guice はそれらをすべて結合し、互いの依存関係を満足させます。

  2. プロバイダーはさまざまなインスタンスを返すことができ、通常はそうしますが、キーを区別するのに役立たないことは間違いありません。Properties インスタンスを直接注入するのが難しすぎる場合は、代わりに軽量のファクトリを作成することを検討してください。

    public class ConfigOracle {
      @Inject private Properties properties;
    
      public String getAsString(String key) { ... }
      public int getAsInt(String key) { ... }
    }
    
    public class SomeConfigUser {
      @Inject private ConfigOracle configOracle;
    
      public void doStuff() {
        doStuffBasedOn(configOracle.getAsString("my.properties.key"));
      }
    }
    
  3. Binderモジュールに a (またはその他のもの)を挿入する必要はありません。

    • を実装するとModulebinderが のパラメータになりますconfigure()。必要に応じて拡張するAbstractModule場合は、binder()メソッドを呼び出すだけです。
    • 必要に応じて、コンストラクター引数を介して依存関係をモジュールに渡すことができます。これは、モジュールが作成するバインディングを変更する唯一の方法です (私に関する限り)。
    • Injector を介してモジュールを作成できない理由はありませんが、最初に Injector を用意する必要があります。
    • Injector から他のインスタンスが必要な場合は、いつでもフィールド/メソッド/コンストラクターを使用してProvider実装を記述したり、メソッドでパラメーターを取得したりすることもできます (依存関係が自動的に入力されます)。@Inject@Provides

全体として、私はまだ子インジェクターのアプローチを支持しています(リンクに感謝し、以前の回答を称賛してください!)。これは、「注入されたインスタンスに基づく動的バインディング」の説明に最もよく適合し、文字通り次のように単純になります。

class PropertiesModule extends AbstractModule {
  Properties properties;

  PropertiesModule(Properties properties) {
    this.properties = properties;
  }

  @Override public void configure() {
    Names.bindProperties(binder(), properties);
  }
}

Injector oldInjector = Guice.createInjector(allYourOtherModules);
Module myModule = new PropertiesModule(oldInjector.get(Properties.class));
Injector injector = oldInjector.createChildInjector(myModule);
于 2012-11-06T04:18:41.873 に答える