-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Injections
How Guice initializes your objects
The dependency injection pattern separates behaviour from dependency resolution. Rather than looking up dependencies directly or from factories, the pattern recommends that dependencies are passed in. The process of setting dependencies into an object is called injection.
Constructor injection combines instantiation with injection. To use it, annotate
the constructor with the @Inject
annotation. This constructor should accept
class dependencies as parameters. Most constructors will then assign the
parameters to final fields.
public class RealBillingService implements BillingService {
private final CreditCardProcessor processorProvider;
private final TransactionLog transactionLogProvider;
@Inject
RealBillingService(CreditCardProcessor processorProvider,
TransactionLog transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
If your class has no @Inject
-annotated constructor, Guice will use a public,
no-arguments constructor if it exists. Prefer the annotation, which documents
that the type participates in dependency injection.
Constructor injection works nicely with unit testing. If your class accepts all of its dependencies in a single constructor, you won't accidentally forget to set a dependency. When a new dependency is introduced, all of the calling code conveniently breaks! Fix the compile errors and you can be confident that everything is properly wired up.
WARNING: Method injection implies that the class being injected into is mutable, which should be avoided in general. So prefer constructor injection over method injection.
Guice can inject methods that have the @Inject
annotation. Dependencies take
the form of parameters, which the injector resolves before invoking the method.
Injected methods may have any number of parameters, and the method name does not
impact injection.
public class PayPalCreditCardProcessor implements CreditCardProcessor {
private static final String DEFAULT_API_KEY = "development-use-only";
private String apiKey = DEFAULT_API_KEY;
@Inject
public void setApiKey(@Named("PayPal API key") String apiKey) {
this.apiKey = apiKey;
}
WARNING: Same as method injection, field injection implies that the class being injected into is mutable, which should be avoided in general. So prefer constructor injection over field injection.
Guice injects fields with the @Inject
annotation. This is the most concise
injection, but the least testable.
public class DatabaseTransactionLogProvider implements Provider<TransactionLog> {
@Inject Connection connection;
public TransactionLog get() {
return new DatabaseTransactionLog(connection);
}
}
Avoid using field injection with final
fields, which has
weak semantics.
TIP: Prefer OptionalBinder
over @Inject(optional = true)
.
Occasionally it's convenient to use a dependency when it exists and to fall back
to a default when it doesn't. Method and field injections may be optional, which
causes Guice to silently ignore them when the dependencies aren't available. To
use optional injection, apply the @Inject(optional=true)
annotation:
public class PayPalCreditCardProcessor implements CreditCardProcessor {
private static final String SANDBOX_API_KEY = "development-use-only";
private String apiKey = SANDBOX_API_KEY;
@Inject(optional=true)
public void setApiKey(@Named("PayPal API key") String apiKey) {
this.apiKey = apiKey;
}
Mixing optional injection and just-in-time bindings may yield surprising
results. For example, the following field is always injected even when Date
is
not explicitly bound. This is because Date
has a public no-arguments
constructor that is eligible for just-in-time bindings.
@Inject(optional=true) Date launchDate;
Method and field injection can be used to initialize an existing instance. You
can use the Injector.injectMembers
API:
public static void main(String[] args) {
Injector injector = Guice.createInjector(...);
CreditCardProcessor creditCardProcessor = new PayPalCreditCardProcessor();
injector.injectMembers(creditCardProcessor);
When
migrating an application
from static factories to Guice, it is possible to change incrementally. Static
injection is a helpful crutch here. It makes it possible for objects to
partially participate in dependency injection, by gaining access to injected
types without being injected themselves. Use requestStaticInjection()
in a
module to specify classes to be injected at injector-creation time:
@Override public void configure() {
requestStaticInjection(ProcessorFactory.class);
...
}
Guice will inject class's static members that have the @Inject
annotation:
class ProcessorFactory {
@Inject static Provider<Processor> processorProvider;
/**
* @deprecated prefer to inject your processor instead.
*/
@Deprecated
public static Processor getInstance() {
return processorProvider.get();
}
}
Static members will not be injected at instance-injection time. This API is not recommended for general use because it suffers many of the same problems as static factories: it's clumsy to test, it makes dependencies opaque, and it relies on global state.
Guice automatically performs field and method injections on the following type of objects:
- instances passed to
toInstance()
in a bind statement - provider instances passed to
toProvider()
in a bind statement
Those injections are performed as part of injector creation.
An injection point is a place in the code where Guice has been asked to inject a dependency.
Example injection points:
- parameters of an injectable constructor
- parameters of a @Provides method
- parameters of an
@Inject
annotated method - fields annotated with
@Inject
-
User's Guide
-
Integration
-
Extensions
-
Internals
-
Releases
-
Community