カスタムインジェクション
標準的な@Injectによる注入のほか、Guiceはカスタム注入のためのフックを提供している。 これにより、それ自身のセマンティックスやアノテーションを持つ他のフレームワークのホストをGuiceとすることができる。 多くの開発者は直接的にカスタム注入を使うことはないだろうが、(訳注:Guiceの?)エクステンションやサードパーティライブラリでこれらを目にすることがあるかもしれない。 それぞれのカスタム注入についてはそれぞれタイプリスナ、インジェクションリスナと登録が必要である。
Guiceが注入を行うとき、TypeListenerはその型を通知される。 一つの型について一度だけ通知されるので、その型のメンバーを列挙するなどの特に多い操作を行うのにもっとも適切である。 With their inspection complete, type listeners may register instance listeners for values as they're injected.
MembersInjectorsとInjectionListenersは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); } } }