カスタムインジェクション
標準的な@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);
}
}
}