My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
Scopes  
Updated Oct 16, 2011 by sberlin

Scopes

By default, Guice returns a new instance each time it supplies a value. This behaviour is configurable via scopes. Scopes allow you to reuse instances: for the lifetime of an application (@Singleton), a session (@SessionScoped), or a request (@RequestScoped). Guice includes a servlet extension that defines scopes for web apps. Custom scopes can be written for other types of applications.

Applying Scopes

Guice uses annotations to identify scopes. Specify the scope for a type by applying the scope annotation to the implementation class. As well as being functional, this annotation also serves as documentation. For example, @Singleton indicates that the class is intended to be threadsafe.

@Singleton
public class InMemoryTransactionLog implements TransactionLog {
  /* everything here should be threadsafe! */
}

Scopes can also be configured in bind statements:

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

And by annotating @Provides methods:

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

If there's conflicting scopes on a type and in a bind() statement, the bind() statement's scope will be used. If a type is annotated with a scope that you don't want, bind it to Scopes.NO_SCOPE.

In linked bindings, scopes apply to the binding source, not the binding target. Suppose we have a class Applebees that implements both Bar and Grill interfaces. These bindings allow for two instances of that type, one for Bars and another for Grills:

  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 to be created, use a @Singleton annotation on the declaration for that class. Or add another binding:

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

This binding makes the other two .in(Singleton.class) clauses above unnecessary.

The in() clause accepts either a scoping annotation like RequestScoped.class and also Scope instances like ServletScopes.REQUEST:

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

The annotation is preferred because it allows the module to be reused in different types of applications. For example, an @RequestScoped object could be scoped to the HTTP request in a web app and to the RPC when it's in an API server.

Eager Singletons

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.

Comment by project member limpbiz...@gmail.com, Apr 8, 2009

Sam Berlin implemented @LazySingleton, which is lazy in Stage.PRODUCTION.

Comment by patel.na...@gmail.com, Oct 7, 2009

Hi, What do you mean by Stateful object and Stateless object in "Choosing a scope" topic. If Object is stateless then why should Guice create new object?? (Bcoz, If its stateless then Singleton does not harm anyway..)

Comment by project member crazybob...@gmail.com, Oct 7, 2009

If the object truly is stateless, it's faster for Guice to create a new instance than it is to retrieve a singleton. If Guice creates a new instance every time, it can bypass the scoping layer entirely, not to mention the logic inside the singleton scope.

Comment by patel.na...@gmail.com, Oct 9, 2009

Whoa... I got reply from BOB LEE.. The CRAZY BOB LEE.. Got your point.. Thanks..

Comment by fyel...@gmail.com, Nov 16, 2009

I can't find anywhere in the documentation where it actually says what a "request" or "session" is. How do I indicate the start and end of request or session? Why is one single-threaded and the other multi-threaded? It would be nice if this were more explicit (or this page pointed to other documentation.)

Comment by project member dha...@gmail.com, Nov 16, 2009

it is an HTTP request or HTTP session respectively. This is canonical across web apps and particularly the Java Servlet programming model.

Comment by MrHarpre...@gmail.com, Feb 8, 2010

I have a request scoped class 'A' that is injected using JustInTime? bindings. Now if such class is injected in multiple classes, will a new instance of 'A' class be created and then injected or will the same instance that is created for the current request be injected into all classes for that request. I mean to ask like if I add some data to class 'A' using a class 'B' ('A' is injected into 'B' using JustInTime? binding), will this data be available to class 'C' also when 'A' is injected into class 'C' in the same request? Also is there any difference in the behaviour if bindings is not JustInTime? but explicit bindings.

Comment by rausc...@gmail.com, Mar 11, 2010

I second @fyellin's concerns: For unit testing, it would be helpful if one could simulate a new session being started. How does one do that?

Comment by thang...@gmail.com, Apr 23, 2010

Your class is original stateless (has no instance variables). As soon as your class is refactored using constructor DI pattern, there is NO WAY that should this class be used in singleton scope.

It is because you can't determine whether an instance of this class is stateful or stateless without knowing whether each of its instance variables is stateful or stateless.

Without using injection, the state of an instance of this class is static determination (meaning you can confirm if it is stateful or stateless by looking into codes). With injection, the state of an instance of this class is runtime determination.

So if your class has class variables and they are injectable, you should avoid using singleton scope for this class.

Comment by j2DbParser@gmail.com, May 22, 2010

How to test Singletons?

Injector injector = Guice.createInjector(); IService ser = injector.getInstance(IService.class); System.out.println("ser=" + ser); ser = injector.getInstance(IService.class); System.out.println("ser=" + ser);

So I need static field for singletons to work and GuiceFactory? to use Guice in my app, how do I pass module into injector?

Comment by j2DbParser@gmail.com, May 22, 2010

After googling I found

If you now wanted to have one type instance per JVM, I suggest that you roll your own Scope implementation. Try to stay away from manual singletons: they are error prone and make testing your code harder. so guice doesnt support real singletons :(

Comment by project member ffa...@gmail.com, Feb 3, 2011

Please ask questions on the groups mailing list (http://groups.google.com/group/google-guice), thanks.

Comment by kristian...@gmail.com, Feb 16, 2011

Can someone confirm whether using @Provides is effectively the same as using a provider ? Little confused between the two.

Comment by tuxSla...@gmail.com, Feb 21, 2011

Why don't you provide "Thread" scope too for non-web applications? It looks logical to have such scope and its a tricky to implement without AOP.

Comment by scottro...@gmail.com, Feb 22, 2011

I was just wondering if there is any way to implement a callback to perform some logic when an object goes out of "Scope" ? For example, I have a Request scoped @Provides method, that creats an object and does some initialization on it, I need a way to do some cleanup when the scope is exiting. -thanks

Comment by sne...@gmail.com, Mar 15, 2011

I'd like to see the "@Provides @Singleton" example expanded. Is it suppossed to call a "new" object like the documentation? Seems stange for a singleton pattern.

DatabaseTransactionLog? transactionLog = new DatabaseTransactionLog?(); transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza"); transactionLog.setThreadPoolSize(30); return transactionLog;

Comment by cgdec...@gmail.com, Mar 15, 2011

As with things bound using bind(...).to(...), Guice handles the scoping for you. In the case of an @Provides @Singleton provider method, it'll ensure that it only calls the method once and reuses the object that is returned.

Comment by davec...@gmail.com, Aug 31, 2011

There's a massive conceptual problem regarding @Singleton scope and default scope. A @Singleton that depends on a default scope object is wholly incompatible, just as much as having @Singleton depend on an object with @Session or @Request scope. The javadoc states that @Singleton indicates thread safety: that's about as good as Java gets in terms of a binding contract between your objects and thread safety and immutability (oh, scala, I miss you).

This is exactly what thang...@gmail states above... except that the problem isn't with using the universally accepted singleton pattern, the problem is the notion that using the default scope is in any way useful or safe. Or architecturally valid. For the reasons he stated. Unless you're new to Java, coming from a PHP worldview, and every single object is default scoped and each thread uses a whole new instance of your application's objects.

The whole point of DI is to remove tight, static coupling between objects. This is done to provide proper abstraction and promoting good unit testing (that means readable, clean code). At some point, your application has some object that calls a method on another object that has been injected. If that object is not @Singleton scoped, you probably had to call Injector.getInstance(). That call right there is a tight coupling, breaking the DI paradigm, introducing non-unit-testable code.

The idea that performance is some sort of valid excuse for using the default scope is absolute nonsense. Object construction is not a performance issue. If your objects take too long to construct, you're doing too much in your constructor. If your application takes a few seconds to start up... you don't really have a performance issue.

Calling Injector.getInstance() is bad. Mixing @Singleton and default scope is a confusing, hidden contract. Sure, you know what you did, but does your team? After you leave? After they leave?

Guice ought to throw an error at startup if a @Singleton depends on any other scope. I cannot think of a situation where allowing them to be mixed would be intended.

Comment by davec...@gmail.com, Aug 31, 2011

A better pattern to use when dealing stateful objects that require dependencies is create a singleton factory. It contains the necessary dependencies, and has a method that takes in the state that the stateful object requires. You can mock out the factory, ignore what should be transparent DI in the test, and avoid mixing scopes.

Comment by vfunst...@gmail.com, Sep 22, 2011

davec..., you can think of Injector as an object factory, calls to which will be replacing constructor invocations that would otherwise contain hardwired dependencies. What does this have to do with scoping though? Depending on how you tell it to scope your objects, Guice will do the right thing. Either I don't get your point, or you don't really get the concept of DI in general.

Comment by clifford...@gmail.com, Jan 4, 2012

Spring choose singleton as the default scope for it's IoC, Guice choose instance (what spring calls 'prototype'). Just curious what motivated this decision?

Comment by project member mccu...@gmail.com, Jan 5, 2012

Having 'prototype' or 'per-instance' scope as the default makes sense when you look into the design of Guice and the re-usability of Providers - imho the main point being that you can build a singleton on top of a per-instance Provider, but not the other way round.


Sign in to add a comment
Powered by Google Project Hosting