Guice @提供方法与提供者类 [英] Guice @Provides Methods vs Provider Classes
问题描述
Provider
的类,每个注入需要一个注册,而且它们主要有一行 get
方法。 每当我需要一个新的提供者时,开始创建一个新的类。在我的模块
中反过来使用提供者类超过 @Provides
方法有什么好处吗? p>
据我所知,他们完全等同于大多数简单的案例。
/ **
*类风格的提供者。
*在模块中:bind(Foo.class).annotatedWith(Quux.class).toProvider(MyProvider.class);
* /
class MyProvider实现Provider&Foo> {
@Inject Dep dep; //各种注入工作,包括构造器注入。
@Override public Foo get(){
return dep.provisionFoo(bar,baz);
}
}
/ **
*方法式提供者。 configure()可以是空的,但不一定是。
* /
class MyModule extends AbstractModule {
/ **名称无关紧要。 Dep自动注入* /
@Provides @Quux public Foo createFoo(Dep dep){
return dep.provisionFoo(bar,baz);
}
@Override public void configure(){/ *这里没有必要* /}
}
在任何一种风格中,Guice允许您注入 Foo
和 Provider&Foo>
,即使该键绑定到一个类或实例。如果直接获取实例,Guice会自动调用 get
,如果不存在,则创建一个隐含的 Provider&Foo>
。绑定注释以两种样式工作。
@Provides的主要优点是紧凑,特别是与匿名内部提供者实现相比。但是请注意,您可能需要几种情况来支持Provider类:
-
您可以创建自己的长期提供者实例,可能有构造函数参数,并将键绑定到这些实例,而不是类文字。
bind Foo.class).toProvider(new FooProvisioner(bar,baz));
-
如果您使用的是与JSR 330(javax.inject)兼容的框架,可以轻松地绑定到javax.inject.Provider类或实例。 com.google.inject.Provider扩展了该接口。
bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
-
您的提供商可能很复杂,无法考虑到自己的课程。根据您的测试结构,以这种方式测试您的供应商可能会更容易。
-
提供商可以扩展抽象类。使用@Provides方法可能并不容易或直观。
-
您可以直接将多个键绑定到同一个Provider。每个@Provides方法只会生成一个绑定,尽管您可以将其他键绑定到键(@Quux Foo),并让Guice执行第二次查找。
-
如果您想(例如)缓存或记录实例而不使用Guice范围或绑定,则提供商很容易进行装饰或包装。
bind(Foo.class).toProvider(new Cache(new FooProvisioner(bar,baz)));
重要:虽然这是Guice无法创建的类的一个很好的策略,但请记住,Guice可以自动创建并注入 Provider< T>
对于您绑定
的任何T,包括到类名,密钥或实例。不需要创建一个明确的提供者,除非你自己涉及到实际的逻辑。
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?
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.
这篇关于Guice @提供方法与提供者类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!