-
Notifications
You must be signed in to change notification settings - Fork 180
Best Practices
This page provides examples and best practices guidelines to follow when writing DI friendly code
Don’t allocate data or have any conditional logic in a Guice module.
Unless you are writing a generic framework most situations in which you want to Inject the injector can be solved by writing a Provider.
When writing libraries keep in mind that classpath scanning of AutoBindSingleton classes will result in those classes being created eagerly when the injector is created. Too broad a set of a packages to scan can result in unwanted singletons being created.
Annotating a Provider with @Singleton ensures that the Provider is a singleton and not the type T itself. Every injection or call to .get() will return a new instance of T. To make T a singleton either do bind(T.class).toProvider(TProvider.class).in(Scopes.Singleton) or implement SingletonProvider instead of Provider.
The following example shows how to use multi bindings to create an extensible mechanism for constructing a polymorphic type. Note that new implementation types can be added simply by adding another binding to the map binder. This can be done in any Guice module
public class FooProvider implements Provider<Foo> {
@Configuration(value="foo.type")
private String type;
private final Map<String, Provider<Foo>> providers;
@Inject
FooProvider(Map<String, Provider<Foo>> providers) {
this.providers = providers;
}
public Foo get() {
return providers.get(type).get();
}
}
public class MyMainModule extends AbstractModule {
protected void configure() {
bind(Foo.class).toProvider(FooProvider.class).in(Scopes.SINGLETON);
}
// - or -
@Provides
@Singleton
public Foo getFoo(Config config, Map<String, Provider<Foo>> impls) {
return impls.get(config.getString("foo.type")).get();
}
}
public class FooModule1 extends AbstractModule {
public void configure() {
MapBinder.newMapBinder(binder(), String.class, Foo.class)
.addBinding("foo1")
.to(FooImpl1.class).in(Scopes.SINGLETON);
}
}
public class FooModule2 extends AbstractModule {
public void configure() {
MapBinder.newMapBinder(binder(), String.class, Foo.class)
.addBinding("foo2")
.to(FooImpl2.class).in(Scopes.SINGLETON);
}
}
Coming soon..
For injectable classes first create an interface and specify a default implementation using @ImplementedBy. This will make it easier to override the implementation in a binding. Note that binding in a guice module overrides @ImplementedBy without complaining about existing bindings.
- Home
- Getting Started
- Bootstrapping
- Lifecycle Management
- Auto Binding
- Module-Dependencies
- Warm Up
- Configuration Mapping
- Field Validation
- Lazy Singleton
- Concurrent Singleton
- Generic Binding Annotations
- LifecycleListener
- Governator Phases
- Grapher Integration
- JUnit Testing
- FAQ
- Best Practices
- Spring, PicoContainer, Etc.
- Javadoc
- End-to-End Examples