Author: limpbizkit
Date: Thu Jan  1 16:49:21 2009
New Revision: 779

Modified:
    wiki/Scopes.wiki

Log:
Edited wiki page through web user interface.

Modified: wiki/Scopes.wiki
==============================================================================
--- wiki/Scopes.wiki    (original)
+++ wiki/Scopes.wiki    Thu Jan  1 16:49:21 2009
@@ -1,36 +1,15 @@
-#summary Overview of writing custom scopes for Guice
+=Scopes=

-= Introduction =
+==Choosing a scope==
+If the object is *stateful*, the scoping should be obvious.  
Per-application is `...@singleton`, per-request is `...@requestscoped`, etc. 
You  
may need to write a [CustomScopes custom scope]. 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.

-Scopes are one of Guice's most powerful features.
+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.

-= Applying Scopes =
-
-Prefer to apply scopes using an annotation on the implementing class. This  
provides helpful information to the code's maintainer. For example,  
`...@singleton` indicates that a class must be threadsafe.
-
-Scopes are applied to the binding source, not the binding target. For  
example, suppose we have a class `Applebees` that implements both `Bar` and  
`Grill` interfaces. These bindings will allow for *two* instances of that  
type, one for `Bar`s and another for `Grill`s:
-{{{
-  bind(Bar.class).to(Applebees.class).in(Singleton.class);
-  bind(Grill.class).to(Applebees.class).in(Singleton.class);
-}}}
-This is because the scopes apply to the bound type (`Bar`, `Grill`), not  
the type that satisfies that binding (`Applebees`). To allow only a single  
instance of our implementation class to be created, use a `...@singleton`  
annotation on the declaration for that class. Or add yet another binding:
-{{{
-  bind(Applebees.class).in(Singleton.class);
-}}}
-This binding makes the other two `.in(Singleton.class)` clauses above  
unnecessary.
-
-Prefer to bind with the scope annotation rather than the scope instance:
-{{{
-  // good:
-  bind(Foo.class).to(RealFoo.class).in(ServletScopes.REQUEST);
-
-  // better:
-  bind(Foo.class).to(RealFoo.class).in(RequestScoped.class);
-}}}
-This way you can reuse the module in a non-servlets environment by  
specifying a different scope to implement for `RequestScoped.class`. Even  
better, use the `...@requestscoped` annotation on the implementation class.
-
-= Eager Singletons =

+==Eager Singletons==
  Guice can build your singletons either eagerly or lazily. 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* ||
@@ -41,183 +20,33 @@

  `*` 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.

-= Custom Scopes =

-It is generally recommended that users *do not* write their own custom  
scopes -- the built-in scopes should be sufficient for most applications.  
If you're writing a web application, the `ServletModule` provides simple,  
well tested scope implementations for HTTP requests and HTTP sessions.
+==Scopes and Concurrency==
+Classes annotated `...@singleton` and `...@sessionscoped` *must be 
threadsafe*.  
Everything that's injected into these classes must also be threadsafe. Use  
[MinimizeMutability minimize mutability] to limit the amount of state that  
requires concurrency protection.

-Creating custom scopes is a multistep process:
-   # Define a scoping annotation
-   # Implementing the `Scope` interface
-   # Attaching the scope annotation to the implementation
-   # Triggering scope entry and exit
+...@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.

-==Defining a scoping annotation==
-The scoping annotation identifies your scope. You'll use it to annotate  
Guice-constructed types, `...@provides` methods, and in the `in()` clause of a  
bind statement. Copy-and-customize this code to define your scoping  
annotation:
-{{{
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import java.lang.annotation.Target;

-...@target({ TYPE, METHOD }) @Retention(RUNTIME) @ScopeAnnotation
-public @interface BatchScoped {}
-}}}
-*Tip:* If your scope represents a request or session (such as for SOAP  
requests), consider using the `RequestScoped` and `SessionScoped`  
annotations from Guice's servlet extension. Otherwise, you may import the  
wrong annotation by mistake. That problem can be quite frustrating to debug.
+==Applying Scopes==
+Prefer to apply scopes using an annotation on the implementing class. This  
provides helpful information to the code's maintainer. For example,  
`...@singleton` indicates that a class must be threadsafe.

-==Implementing Scope==
-The scope interface ensures there's at most one type instance for each  
scope instance. `SimpleScope` is a decent starting point for a per-thread  
implementation. Copy this class into your project and tweak it to suit your  
needs.
+Scopes are applied to the binding source, not the binding target. For  
example, suppose we have a class `Applebees` that implements both `Bar` and  
`Grill` interfaces. These bindings will allow for *two* instances of that  
type, one for `Bar`s and another for `Grill`s:
  {{{
-import static com.google.common.base.Preconditions.checkState;
-import com.google.common.collect.Maps;
-import com.google.inject.Key;
-import com.google.inject.OutOfScopeException;
-import com.google.inject.Provider;
-import com.google.inject.Scope;
-import java.util.Map;
-
-/**
- * Scopes a single execution of a block of code. Apply this scope with a
- * try/finally block: <pre>   {...@code
- *
- *   scope.enter();
- *   try {
- *     // explicitly seed some seed objects...
- *     scope.seed(Key.get(SomeObject.class), someObject);
- *     // create and access scoped objects
- *   } finally {
- *     scope.exit();
- *   }
- * }</pre>
- *
- * The scope can be initialized with one or more seed values by calling
- * <code>seed(key, value)</code> before the injector will be called upon to
- * provide for this key. A typical use is for a servlet filter to  
enter/exit the
- * scope, representing a Request Scope, and seed HttpServletRequest and
- * HttpServletResponse.  For each key inserted with seed(), it's good  
practice
- * (since you have to provide <i>some</i> binding anyhow) to include a
- * corresponding binding that will throw an exception if Guice is asked to
- * provide for that key if it was not yet seeded: <pre>   {...@code
- *
- *   bind(key)
- *       .toProvider(SimpleScope.<KeyClass>seededKeyProvider())
- *       .in(ScopeAnnotation.class);
- * }</pre>
- *
- * @author Jesse Wilson
- * @author Fedor Karpelevitch
- */
-public class SimpleScope implements Scope {
-
-  private static final Provider<Object> SEEDED_KEY_PROVIDER =
-      new Provider<Object>() {
-        public Object get() {
-          throw new IllegalStateException("If you got here then it means  
that" +
-              " your code asked for scoped object which should have been" +
-              " explicitly seeded in this scope by calling" +
-              " SimpleScope.seed(), but was not.");
-        }
-      };
-  private final ThreadLocal<Map<Key<?>, Object>> values
-      = new ThreadLocal<Map<Key<?>, Object>>();
-
-  public void enter() {
-    checkState(values.get() == null, "A scoping block is already in  
progress");
-    values.set(Maps.<Key<?>, Object>newHashMap());
-  }
-
-  public void exit() {
-    checkState(values.get() != null, "No scoping block in progress");
-    values.remove();
-  }
-
-  public <T> void seed(Key<T> key, T value) {
-    Map<Key<?>, Object> scopedObjects = getScopedObjectMap(key);
-    checkState(!scopedObjects.containsKey(key), "A value for the key %s  
was " +
-        "already seeded in this scope. Old value: %s New value: %s", key,
-        scopedObjects.get(key), value);
-    scopedObjects.put(key, value);
-  }
-
-  public <T> void seed(Class<T> clazz, T value) {
-    seed(Key.get(clazz), value);
-  }
-
-  public <T> Provider<T> scope(final Key<T> key, final Provider<T>  
unscoped) {
-    return new Provider<T>() {
-      public T get() {
-        Map<Key<?>, Object> scopedObjects = getScopedObjectMap(key);
-
-        @SuppressWarnings("unchecked")
-        T current = (T) scopedObjects.get(key);
-        if (current == null && !scopedObjects.containsKey(key)) {
-          current = unscoped.get();
-          scopedObjects.put(key, current);
-        }
-        return current;
-      }
-    };
-  }
-
-  private <T> Map<Key<?>, Object> getScopedObjectMap(Key<T> key) {
-    Map<Key<?>, Object> scopedObjects = values.get();
-    if (scopedObjects == null) {
-      throw new OutOfScopeException("Cannot access " + key
-          + " outside of a scoping block");
-    }
-    return scopedObjects;
-  }
-
-  /**
-   * Returns a provider that always throws exception complaining that the  
object
-   * in question must be seeded before it can be injected.
-   *
-   * @return typed provider
-   */
-  @SuppressWarnings({"unchecked"})
-  public static <T> Provider<T> seededKeyProvider() {
-    return (Provider<T>) SEEDED_KEY_PROVIDER;
-  }
-}
+  bind(Bar.class).to(Applebees.class).in(Singleton.class);
+  bind(Grill.class).to(Applebees.class).in(Singleton.class);
  }}}
-
-==Binding the annotation to the implementation==
-You must attach your scoping annotation to the corresponding scope  
implementation. Just like bindings, you can configure this in your module's  
`configure()` method. Usually you'll also bind the scope itself, so  
interceptors or filters can use it.
+This is because the scopes apply to the bound type (`Bar`, `Grill`), not  
the type that satisfies that binding (`Applebees`). To allow only a single  
instance of our implementation class to be created, use a `...@singleton`  
annotation on the declaration for that class. Or add yet another binding:
  {{{
-public class BatchScopeModule {
-  public void configure() {
-    SimpleScope batchScope = new SimpleScope();
-
-    // tell Guice about the scope
-    bindScope(BatchScoped.class, batchScope);
-
-    // make our scope instance injectable
-    bind(SimpleScope.class)
-        .annotatedWith(Names.named("batchScope")
-        .toInstance(batchScope);
-  }
-}
+  bind(Applebees.class).in(Singleton.class);
  }}}
+This binding makes the other two `.in(Singleton.class)` clauses above  
unnecessary.

-==Triggering the Scope==
-`SimpleScope` requires that you manually enter and exit the scope. Usually  
this lives in some low-level infrastructure code, like a filter or  
interceptor. Be sure to call `exit()` in a `finally` clause, otherwise the  
scope will be left open when an exception is thrown.
+Prefer to bind with the scope annotation rather than the scope instance:
  {{{
-  @Inject @Named("batchScope") SimpleScope scope;
+  // good:
+  bind(Foo.class).to(RealFoo.class).in(ServletScopes.REQUEST);

-  /**
-   * Runs {...@code runnable} in batch scope.
-   */
-  public void scopeRunnable(Runnable runnable) {
-    scope.enter();
-    try {
-      // explicitly seed some seed objects...
-      scope.seed(Key.get(SomeObject.class), someObject);
-
-      // create and access scoped objects
-      runnable.run();
-
-    } finally {
-      scope.exit();
-    }
-  }
-}}}
\ No newline at end of file
+  // better:
+  bind(Foo.class).to(RealFoo.class).in(RequestScoped.class);
+}}}
+This way you can reuse the module in a non-servlets environment by  
specifying a different scope to implement for `RequestScoped.class`. Even  
better, use the `...@requestscoped` annotation on the implementation class.
\ No newline at end of file

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to