Locked History Actions

Diff for "guice/Manual/UserGuide/InjectingProviders"

Differences between revisions 1 and 2
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
With normal dependency injection, each type gets exactly one instance of each of its dependent types. The RealBillingService gets one CreditCardProcessor and one TransactionLog. When this flexibility is necessary, Guice binds a provider. Providers produce a value when the get() method is invoked: 通常の依存性注入では、各タイプはただ一つのインスタンスを受け取る。
つまり、RealBillingServiceには一つのCreditCardProcessorと一つのTransactionLogである。
しかし、よりフレキシビリティが必要な場合にはGuiceはプロバイダをバインドする。
プロバイダはそのget()メソッドが呼び出される度に一つの値を返す。
Line 9: Line 12:
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. プロバイダのタイプはパラメトライズされており、Provider<TransactionLog>とProvider<CreditCardProcessor>を区別することができる。
値の注入可能なところでは、その代わりにプロバイダを注入することができる。
Line 30: Line 34:
For every binding, annotated or not, the injector has a built-in binding for its provider.
Providers for multiple instances
アノテーションされていようがいまいが、すべてのバインディングはそのプロバイダへのビルトインバインディングを作成する。
Line 33: Line 36:
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: == 複数インスタンスのためのプロバイダ ==

一つの型について複数のインスタンスが必要な場合にプロバイダを使うことができる。
例えば、ピザのチャージが失敗したときに、アプリケーションはサマリエントリと詳細を保存することにしよう。
プロバイダを使うと、必要な時にはいつでも新しいエントリを作成することができる。
Line 56: Line 64:
== Providers for lazy loading ==
Line 58: Line 65:
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: == 遅延ローディングのためのプロバイダ ==

もし、あるタイプの依存(実装)を作成するのが特に高価(遅い、メモリを食うなど)な場合、プロバイダを使ってその作業を遅らせることができる。
これは、必ずしも依存が必要でないことがある場合に有用である。
Line 76: Line 86:
== Providers for Mixing Scopes ==
Line 78: Line 87:
It is an error to depend on an object in a narrower scope. Suppose you have a singleton transaction log that needs on the request-scoped current user. Should you inject the user directly, things break because the user changes from request to request. Since providers can produce values on-demand, they enable you to mix scopes safely: == スコープミキシングのためのプロバイダ ==

より狭いスコープのオブジェクトに依存することは間違いである。
例えば、シングルトンのトランザクションログオブジェクトがリクエストスコープのcurrent userを要求するとする。
userを直接的に注入してしまうと滅茶苦茶になってしまう、なぜならuserはリクエストごとに異なるからである。
プロバイダは値をオンデマンドで作成するため、スコープを安全にミックスすることができる。

= プロバイダをインジェクトする ==

通常の依存性注入では、各タイプはただ一つのインスタンスを受け取る。 つまり、RealBillingServiceには一つのCreditCardProcessorと一つのTransactionLogである。 しかし、よりフレキシビリティが必要な場合にはGuiceはプロバイダをバインドする。 プロバイダはそのget()メソッドが呼び出される度に一つの値を返す。

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

プロバイダのタイプはパラメトライズされており、Provider<TransactionLog>とProvider<CreditCardProcessor>を区別することができる。 値の注入可能なところでは、その代わりにプロバイダを注入することができる。

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

アノテーションされていようがいまいが、すべてのバインディングはそのプロバイダへのビルトインバインディングを作成する。

複数インスタンスのためのプロバイダ

一つの型について複数のインスタンスが必要な場合にプロバイダを使うことができる。 例えば、ピザのチャージが失敗したときに、アプリケーションはサマリエントリと詳細を保存することにしよう。 プロバイダを使うと、必要な時にはいつでも新しいエントリを作成することができる。

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

遅延ローディングのためのプロバイダ

もし、あるタイプの依存(実装)を作成するのが特に高価(遅い、メモリを食うなど)な場合、プロバイダを使ってその作業を遅らせることができる。 これは、必ずしも依存が必要でないことがある場合に有用である。

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

スコープミキシングのためのプロバイダ

より狭いスコープのオブジェクトに依存することは間違いである。 例えば、シングルトンのトランザクションログオブジェクトがリクエストスコープのcurrent userを要求するとする。 userを直接的に注入してしまうと滅茶苦茶になってしまう、なぜならuserはリクエストごとに異なるからである。 プロバイダは値をオンデマンドで作成するため、スコープを安全にミックスすることができる。

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