Implicit Bindings
In the fortunes example, you've probably noticed that I never made an explicit binding for Chef. This is because bindings don't always have to be explicit. As a rule of thumb, if there is no ambiguity, Guice will figure it out for you. This applies to concrete classes. As shown in Listing 15, I could have configured an explicit binding to Chef. This is kind of redundant, so I usually don't bind concrete classes explicitly.
public class ExplicitChefModule extends AbstractModule { protected void configure() { // no to(...) because you can't bind to the same class bind(Chef.class); } }
Next to these implicit bindings, provided by Guice, you can also reduce configuration yourself when working with interfaces. Guice comes with an @ImplementedBy annotation that lets you specify which concrete class implementation to use for an interface. For example, Listing 16 shows the same FortuneService interface from Listing 2, now changed to use @ImplementedBy.
@ImplementedBy(FortuneServiceImpl.class) public interface FortuneService { String randomFortune(); }
By using @ImplementedBy, you can get rid of modules altogether. Whether that's a good idea or not, I'll leave up to you to decide. I usually stick to modules, because they allow you to change your application's configuration in a single line of code, by including or excluding certain modules when creating the Injector. However, you can use @ImplementedBy to specify a default implementation, and then override it in a Module implementation. That way, when creating an Injector without any modules, you'll always get a default implementation.
Note: Module configuration always takes precedence over annotation configuration.
Scoping
Guice's default behavior is to create a new instance of an object each time that object gets requested or injected. Scopes allow you to customize an object's lifetime. The canonical example is the built-in singleton scope, which makes sure only one instance of an object exists for a given Injector and internal Key. This is much, much better than using singletons manually, because this does not involve using static factory methods (or writing any code at all). But, as with any singleton, you'll have to make sure that your class is thread safe if you're going to access it from multiple threads.
To apply a scope to our FortuneService bindings, we specify either a scope annotation or an instance of the Scope class. For a singleton, these are Singleton.class and Scopes.SINGLETON, respectively. In Listing 17, I mix both of these styles (not recommended).
public class ScopedModule extends AbstractModule { protected void configure() { bind(FortuneService.class) .to(FortuneServiceImpl.class) .in(Singleton.class); bind(FortuneService.class) .annotatedWith(Mega.class) .to(MegaFortuneService.class) .in(Scopes.SINGLETON); } }
You can also apply a scope by directly tagging your class with the @Singleton annotation, but as with @ImplementedBy, bindings in modules always take precedence.
The question that now is, "Do singletons load lazily or eagerly?" The short answer is that this will depend on the Injector's Stage, as I mentioned earlier. If you want to make sure that your singleton is created at application start-up (loaded eagerly), regardless of the Injector's Stage or the binding's usage, you can specify that as in Listing 18.
Tip: Stage.PRODUCTION loads singletons eagerly; Stage.DEVELOPMENT does not.
public class EagerSingletonModule extends AbstractModule { protected void configure() { bind(FortuneService.class) .to(FortuneServiceImpl.class) .asEagerSingleton(); bind(FortuneService.class) .annotatedWith(Mega.class) .to(MegaFortuneService.class) .asEagerSingleton(); } }
Loading singletons eagerly might be useful to execute initialization logic for your application. You can even create dependencies between them in such a way that you're sure they'll come up in the right order. I've only talked about the singleton scope for now, because it's the only scope that ships with core Guice (guice-1.0.jar). The 1.0 distribution also comes with a guice-servlet-1.0.jar archive containing the web-specific (servlet-specific) scopes: request and session.