Revision 1 as of 2009-12-12 01:43:13

Clear message
Locked History Actions

guice/Manual/UserGuide/Scopes

スコープ

デフォルトでは、Guiceは常に新しいインスタンスを作成して返す。 このふるいまいはスコープによって変更可能である。 スコープによってインスタンスを再利用することができる。 つまり、そのライフタイムをアプリケーション(@Singleton)、セッション(@SessionScoped)、リクエスト(@RequestScoped)と区別することができる。

Guiceはウェブアプリ用のスコープを定義するためのサーブレット拡張を提供している。 それ以外のアプリケーションでは、カスタムスコープを作成することができる。

スコープの適用

Guiceはスコープを識別するためにアノテーションを使う。 実装クラスにスコープアノテーションを適用することにより、そのタイプのスコープを指定することができる。 機能的にもそうだが、ドキュメント用ととしてもこれらのアノテーションは役に立つ。 例えば、@Singletonはこのクラスがスレッドセーフであるべきことを示す(訳注:そうとは限らないと思うけど)。

@Singleton
public class InMemoryTransactionLog implements TransactionLog {
  /* ここにあるものはすべてスレッドセーフであること */
}

スコープはbindにおいても指定することができる。

  bind(TransactionLog.class).to(InMemoryTransactionLog.class).in(Singleton.class);

また、@Providesメソッドに指定することもできる。

  @Provides @Singleton
  TransactionLog provideTransactionLog() {
    ...
  }

タイプ(のアノテーション)とbind()でスコープが異なる場合は、bind()の方が優先される。 アノテーションされたスコープをキャンセルしたい場合には、bind()時にScopes.NO_SCOPEを使うことができる。

リンクバインディングにおいては、スコープはバインディングソースの方に適用される。バインディングターゲットではない。 例えば、Bar,Grillインターフェースを実装するApplebeesというクラスがあるとする。 以下の二つのバインディングは二つのインスタンスを許す、一つはBar向けのもの、もう一つはGrill向けのものである。

  bind(Bar.class).to(Applebees.class).in(Singleton.class);
  bind(Grill.class).to(Applebees.class).in(Singleton.class);

なぜかというと、スコープはバインドされるタイプ(Bar, Grill)に適用されるからであり、それらのタイプを満足するバインディング(Applebees)ではないからである。 もしただ一つのインスタンスだけを作成したいのであれば、そのクラスに対して@Singletonアノテーションを使うか、あるいは別のバインディングを使う必要がある。

  bind(Applebees.class).in(Singleton.class);

このバインディングを使うと、他の二つのバインディングの.in(Singleton.class)句は不要になる。

in()句にはRequestScoped.classのようなアノテーションを入れることもできるし、ServletScopes.REQUESTといったインスタンスを入れることもできる。

  bind(UserPreferences.class)
      .toProvider(UserPreferencesProvider.class)
      .in(ServletScopes.REQUEST);

アノテーションを使った方が望ましい。そのモジュールは別のタイプのアプリケーションでも再利用可能だからだ。 例えば、@RequestScopedオブジェクトであれば、ウェブアプリにおけるHTTPリクエストのスコープとして使うこともできるし、 APIサーバのRPCリクエストとして使うことができるからだ。

Eagerシングルトン

Guice has special syntax to define singletons that can be constructed eagerly:

  bind(TransactionLog.class).to(InMemoryTransactionLog.class).asEagerSingleton();

Eager singletons reveal initialization problems sooner, and ensure end-users get a consistent, snappy experience. Lazy singletons enable a faster edit-compile-run development cycle. Use the Stage enum to specify which strategy should be used.

  • || PRODUCTION| DEVELOPMENT| |.asEagerSingleton()| eager| eager| |.in(Singleton.class)| eager| lazy| |.in(Scopes.SINGLETON)| eager| lazy| |@Singleton| eager*| lazy|

* Guice will only eagerly build singletons for the types it knows about. These are the types mentioned in your modules, plus the transitive dependencies of those types. Choosing a scope

If the object is stateful, the scoping should be obvious. Per-application is @Singleton, per-request is @RequestScoped, etc. If the object is stateless and inexpensive to create, scoping is unnecessary. Leave the binding unscoped and Guice will create new instances as they're required.

Singletons are popular in Java applications but they don't provide much value, especially when dependency injection is involved. Although singletons save object creation (and later garbage collection), getting a handle to the single instance requires synchronization. Singletons are most useful for:

  • stateful objects, such as configuration or counters
  • objects that are expensive to construct or lookup
  • objects that tie up resources, such as a database connection pool.

Scopes and Concurrency

Classes annotated @Singleton and @SessionScoped must be threadsafe. Everything that's injected into these classes must also be threadsafe. Minimize mutability to limit the amount of state that requires concurrency protection.

@RequestScoped objects do not need to be threadsafe. It is usually an error for a @Singleton or @SessionScoped object to depend on an @RequestScoped one. Should you require an object in a narrower scope, inject a Provider of that object.