-
Notifications
You must be signed in to change notification settings - Fork 1.7k
InjectingProviders
With normal dependency injection, each type gets exactly one instance of each
of its dependent types. The RealBillingService
gets one CreditCardProcessor
and one TransactionLog
. Sometimes you want more than one instance of your
dependent types. When this flexibility is necessary, Guice binds a provider.
Providers produce a value when the get()
method is invoked:
public interface Provider<T> {
T get();
}
The provider's type is parameterized to differentiate a
Provider<TransactionLog>
from a Provider<CreditCardProcessor>
. Wherever you
inject a value you can inject a provider for that value.
public class RealBillingService implements BillingService {
private final Provider<CreditCardProcessor> processorProvider;
private final Provider<TransactionLog> transactionLogProvider;
@Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
}
}
For every binding, annotated or not, the injector has a built-in binding for its provider.
Use providers when you need multiple instances of the same type. Suppose your application saves a summary entry and a details when a pizza charge fails. With providers, you can get a new entry whenever you need one:
public class LogFileTransactionLog implements TransactionLog {
private final Provider<LogFileEntry> logFileProvider;
@Inject
public LogFileTransactionLog(Provider<LogFileEntry> logFileProvider) {
this.logFileProvider = logFileProvider;
}
public void logChargeResult(ChargeResult result) {
LogFileEntry summaryEntry = logFileProvider.get();
summaryEntry.setText("Charge " + (result.wasSuccessful() ? "success" : "failure"));
summaryEntry.save();
if (!result.wasSuccessful()) {
LogFileEntry detailEntry = logFileProvider.get();
detailEntry.setText("Failure result: " + result);
detailEntry.save();
}
}
If you've got a dependency on a type that is particularly expensive to produce, you can use providers to defer that work. This is especially useful when you don't always need the dependency:
public class DatabaseTransactionLog implements TransactionLog {
private final Provider<Connection> connectionProvider;
@Inject
public DatabaseTransactionLog(Provider<Connection> connectionProvider) {
this.connectionProvider = connectionProvider;
}
public void logChargeResult(ChargeResult result) {
/* only write failed charges to the database */
if (!result.wasSuccessful()) {
Connection connection = connectionProvider.get();
}
}
Directly injecting an object with a narrower scope usually causes unintended
behavior in your application. In the example below, suppose you have a singleton
ConsoleTransactionLog
that depends on the request-scoped current user. If you
were to inject the user directly into the ConsoleTransactionLog
constructor,
the user would only be evaluated once for the lifetime of the application. This
behavior isn't correct because the user changes from request to request.
Instead, you should use a Provider. Since Providers produce values on-demand,
they enable you to mix scopes safely:
@Singleton
public class ConsoleTransactionLog implements TransactionLog {
private final AtomicInteger failureCount = new AtomicInteger();
private final Provider<User> userProvider;
@Inject
public ConsoleTransactionLog(Provider<User> userProvider) {
this.userProvider = userProvider;
}
public void logConnectException(UnreachableException e) {
failureCount.incrementAndGet();
User user = userProvider.get();
System.out.println("Connection failed for " + user + ": " + e.getMessage());
System.out.println("Failure count: " + failureCount.incrementAndGet());
}
-
User's Guide
-
Integration
-
Extensions
-
Internals
-
Releases
-
Community