Guice系列之用户指南(十二)

原文地址:https://code.google.com/p/google-guice/wiki/InjectingProviders

InjectingProviders(注入的提供者):通过注入提供者来产生对象支持依赖注入。

和普通的依赖注入一样,每一种类型都能够确切地获取它所依赖的实例。RealBillingService包含CreditCardProcessor和TransactionLog,当灵活性是必须地时,Guice会绑定一个提供者,当调用get()方法时,提供者会产生一个对象的值。

public interface Provider<T> {
  T get();
}

这个提供者的类型是通过泛型参数来区分的,在Provider和Provider之间。只要是注入值的地方都可以通过注入提供者来代替。

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 */
  }
}

对每一种绑定或者是注解,注入器都有内建绑定的相应的提供者。

Providers for multiple instances(不同实例的提供者):顾名思义。

在使用提供者的过程中,你可能需要一种类型的不同实例。设想当一个披萨支付失败时,你的应用程序正在保存一个概括条目和一个详细订单。用各种提供者,你就能随时获取一个新的条目:

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();
    }
  }

Providers for lazy loading(延时加载的提供者):在提供者里做部分逻辑延迟产生大对象。
当你在获取关于一个类型的依赖,同时这个依赖的创建开销又特别的大时,你能够用提供者来推迟这项工作。当你不是非常需要这个依赖时,这是很有用的:

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();
    }
  }

Providers for Mixing Scopes(混合作用域的提供者):提供者产生不同作用域的对象。
依赖一个很窄的作用域的对象是一个错误,设想你使用了单例的事务日志,但是这个事务日志对当前用户需要用的是请求作用域。如果你直接注入用户就会出错,因为用户是随着请求的改变而改变的。自从提供者能够按需的产生对象值,它们使你安全的混合多个作用域成为可能:

@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());
  }
此条目发表在编程语言分类目录,贴了, 标签。将固定链接加入收藏夹。