I'm working on a fairly large project that has a lot of injections. We're currently using a class that implements Provider
for each injection that needs one, and they mostly have one line get
methods.
It's starting to get annoying to create a new class every time I need a new provider. Is there any benefit to using provider classes over @Provides
methods in my Module
or vice-a-versa?
Providers are used in numerous ways by Guice: When the default means for obtaining instances (an injectable or parameterless constructor) is insufficient for a particular binding, the module can specify a custom Provider instead, to control exactly how Guice creates or obtains instances for the binding.
Dependency Injection for Java Developers with Dagger & Guice As @provides method becomes more complex, this method can be moved to separate classes using Provider interface. Next, you have to map the provider to type. bind(SpellChecker. class).
Dependency Injection for Java Developers with Dagger & Guice Guice provides a way to create bindings with complex objects using @provides method. This methods is being part of Binding Module and provides the complex object to be mapped.
getInstance. Returns the appropriate instance for the given injection type; equivalent to getProvider(type). get() . When feasible, avoid using this method, in favor of having Guice inject your dependencies ahead of time.
As far as I know, they're exactly equivalent for most simple cases.
/**
* Class-style provider.
* In module: bind(Foo.class).annotatedWith(Quux.class).toProvider(MyProvider.class);
*/
class MyProvider implements Provider<Foo> {
@Inject Dep dep; // All sorts of injection work, including constructor injection.
@Override public Foo get() {
return dep.provisionFoo("bar", "baz");
}
}
/**
* Method-style provider. configure() can be empty, but doesn't have to be.
*/
class MyModule extends AbstractModule {
/** Name doesn't matter. Dep is injected automatically. */
@Provides @Quux public Foo createFoo(Dep dep) {
return dep.provisionFoo("bar", "baz");
}
@Override public void configure() { /* nothing needed in here */ }
}
In either style, Guice lets you inject Foo
and Provider<Foo>
, even if the key is bound to a class or instance. Guice automatically calls get
if getting an instance directly and creates an implicit Provider<Foo>
if one doesn't exist. Binding annotations work in both styles.
The main advantage of @Provides is compactness, especially in comparison to anonymous inner Provider implementations. Note, however, that there might be a few cases where you'd want to favor Provider classes:
You can create your own long-lived Provider instances, possibly with constructor parameters, and bind keys to those instances instead of to class literals.
bind(Foo.class).toProvider(new FooProvisioner("bar", "baz"));
If you're using a framework compatible with JSR 330 (javax.inject), you can easily bind to javax.inject.Provider classes or instances. com.google.inject.Provider extends that interface.
bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
Your Provider may be complex enough to factor into its own class. Depending on how you've structured your tests, it may be easier to test your Provider this way.
Providers can extend abstract classes. It may not be easy or intuitive to do this with @Provides methods.
You can bind several keys to the same Provider directly. Each @Provides method produces exactly one binding, though you could bind other keys to the key (@Quux Foo here) and let Guice do a second lookup.
Providers are easy to decorate or wrap, if you wanted to (for instance) cache or memoize instances without using Guice scopes or bindings.
bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
IMPORTANT: Though this is a good strategy for classes that Guice can't create, bear in mind that Guice can automatically create and inject a Provider<T>
for any T that you bind
in any way, including to a class name, key, or instance. No need to create an explicit provider unless there's actual logic of your own involved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With