-
Notifications
You must be signed in to change notification settings - Fork 1.7k
CustomInjections
Performing custom injections with type and injection listeners
In addition to the standard @Inject
-driven injections, Guice includes hooks
for custom injections. This enables Guice to host other frameworks that have
their own injection semantics or annotations. Most developers won't use custom
injections directly; but they may see their use in extensions and third-party
libraries. Each custom injection requires a type listener, an injection
listener, and registration of each.
TypeListeners get notified of the types that Guice injects. Since type listeners are only notified once-per-type, they are the best place to run potentially slow operations, such as enumerating a type's members. With their inspection complete, type listeners may register instance listeners for values as they're injected.
MembersInjectors and InjectionListeners can be used to receive a callback after Guice has injected an instance. The instance is first injected by Guice, then by the custom members injectors, and finally the injection listeners are notified. Since they're notified once-per-instance, these should execute as quickly as possible.
Guice includes built-in support for injecting java.util.Logger
instances that
are named using the type of the injected instance. With the type listener API,
you can inject a org.apache.log4j.Logger
with the same high-fidelity naming.
We'll be injecting fields of this format:
import org.apache.log4j.Logger;
import com.publicobject.log4j.InjectLogger;
public class PaymentService {
@InjectLogger Logger logger;
...
}
We start by registering our custom type listener Log4JTypeListener
in a
module. We use a matcher to select which types we listen for:
@Override protected void configure() {
bindListener(Matchers.any(), new Log4JTypeListener());
}
You can implement the
TypeListener
to scan through a type's fields, looking for Log4J loggers. For each logger
field that's encountered, we register a Log4JMembersInjector
on the passed-in
TypeEncounter:
class Log4JTypeListener implements TypeListener {
public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
Class<?> clazz = typeLiteral.getRawType();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getType() == Logger.class &&
field.isAnnotationPresent(InjectLogger.class)) {
typeEncounter.register(new Log4JMembersInjector<T>(field));
}
}
clazz = clazz.getSuperclass();
}
}
}
Finally, we implement the Log4JMembersInjector
to set the logger. In this
example, we always set the field to the same instance. In your application you
may need to compute a value or request one from a provider.
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);
}
}
}
-
User's Guide
-
Integration
-
Extensions
-
Internals
-
Releases
-
Community