Locked History Actions

guice/Manual/Integration/CustomInjections

カスタムインジェクション

標準的な@Injectによる注入のほか、Guiceはカスタム注入のためのフックを提供している。 これにより、それ自身のセマンティックスやアノテーションを持つ他のフレームワークのホストをGuiceとすることができる。 多くの開発者は直接的にカスタム注入を使うことはないだろうが、(訳注:Guiceの?)エクステンションやサードパーティライブラリでこれらを目にすることがあるかもしれない。 それぞれのカスタム注入についてはそれぞれタイプリスナ、インジェクションリスナと登録が必要である。

Guiceが注入を行うとき、TypeListenerはその型を通知される。 一つの型について一度だけ通知されるので、その型のメンバーを列挙するなどの特に多い操作を行うのにもっとも適切である。 With their inspection complete, type listeners may register instance listeners for values as they're injected.

MembersInjectorsInjectionListenersはGuiceがインスタンスへの注入を行った後でコールバックを受け取ることに使用できる。 インスタンスは最初にGuiceの注入を受け、次にカスタムメンバーインジェクタによる注入を受け、最後にインジェクションリスナに通知される。 それらはインスタンスごとに通知されるため、その実行はできるだけ素早く行う必要がある。

例:Log4Jロガーに注入する

Guiceはjava.util.Loggerインスタンスに注入するビルトインサポートがあり、それらは注入を受けるインスタンスの型の名称が使われる。 タイプリスナAPIを使うことによりorg.apache.log4j.Loggerに対して同様のhigh-fidelityネーミングを行うことができる。 このフォーマットのフィールドに注入してみよう。

import org.apache.log4j.Logger;
import com.publicobject.log4j.InjectLogger;

public class PaymentService {
  @InjectLogger Logger logger;

  ...
}

モジュールにてカスタムタイプリスナLog4JTypeListenerをまず登録する。 matcherを使って、どのタイプをリッスンするかを選択する。

  @Override protected void configure() {
    bindListener(Matchers.any(), new Log4JTypeListener());
  }

TypeListenerにて型のフィールドをスキャンして、Log4Jロガーを探す。 見つかったロガーフィールドそれぞれについて渡されたTypeEncounterにLog4JMembersInjectorを登録する。

  class Log4JTypeListener implements TypeListener {
    public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
      for (Field field : typeLiteral.getRawType().getDeclaredFields()) {
        if (field.getType() == Logger.class
            && field.isAnnotationPresent(InjectLogger.class)) {
          typeEncounter.register(new Log4JMembersInjector<T>(field));
        }
      }
    }
  }

最後にLog4JMembersInjectorをロガーをセットするように実装する。 この例では、フィールドに同じインスタンスをセットするようにしている。 実際のアプリケーションでは、値を導出するか、プロバイダにリクエストするようにする。

  class Log4JMembersInjector<T> implements MembersInjector<T> {
    private final Field field;
    private final Logger logger;

    Log4JMembersInjector(Field field) {
      this.field = field;
      this.logger = Logger.getLogger(field.getDeclaringClass());
      field.setAccessible(true);
    }

    public void injectMembers(T t) {
      try {
        field.set(t, logger);
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      }
    }
  }