Java Guice @Provides 方法与提供者类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28202882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Guice @Provides Methods vs Provider Classes
提问by Eliezer
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.
我正在做一个相当大的项目,有很多注入。我们目前正在使用一个Provider
为每个需要一个注入实现的类,它们大多只有一行get
方法。
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?
每次我需要一个新的提供者时,创建一个新类开始变得很烦人。@Provides
在我的方法上使用提供程序类是否有任何好处,Module
反之亦然?
采纳答案by Jeff Bowman
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.
无论哪种风格,Guice 都允许您注入Foo
and Provider<Foo>
,即使键绑定到类或实例。get
如果直接获取实例,Guice 会自动调用,如果Provider<Foo>
不存在则创建隐式。绑定注释在两种风格中都有效。
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:
@Provides 的主要优点是紧凑性,尤其是与匿名内部 Provider 实现相比。但是请注意,在某些情况下,您可能希望使用 Provider 类:
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")));
您可以创建自己的长期 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);
您的 Provider 可能很复杂,可以考虑到它自己的类中。根据您构建测试的方式,以这种方式测试您的 Provider 可能更容易。
提供者可以扩展抽象类。使用 @Provides 方法执行此操作可能并不容易或不直观。
您可以直接将多个键绑定到同一个 Provider。每个@Provides 方法只生成一个绑定,尽管您可以将其他键绑定到该键(此处为@Quux Foo)并让 Guice 进行第二次查找。
如果您想(例如)在不使用 Guice 范围或绑定的情况下缓存或记忆实例,则提供程序很容易装饰或包装。
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 无法创建的类来说这是一个很好的策略,但请记住,Guice 可以自动Provider<T>
为您bind
以任何方式创建和注入任何 T ,包括类名、键或实例。除非涉及您自己的实际逻辑,否则无需创建显式提供程序。
回答by Jamie J
There is also a difference in how classes are instantiated. For Eg :
类的实例化方式也有所不同。例如:
public class GumProvider implements Provider<Gum> {
public Gum get() {
return new Gum();
}
}
public class GumModule extends AbstractModule {
protected void configure() {
bind(Gum.class).toProvider(GumProvider.class);
//bind(Gum.class).to(GumballMachine.class);
}
}
public class GumballMachine {
@Inject
private Provider<Gum> gumProvider;
Gum gum;
public Gum dispense() {
return gumProvider.get();
}
}
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
Injector injector = Guice.createInjector(new GumModule());
GumballMachine m = injector.getInstance(GumballMachine.class);
System.out.println(m.dispense());
System.out.println(m.dispense());
}
}
This would create an Instance of Gum Per Invocation. Whereas if @Provides were used the same Instance of Gum would be passed to both the Injectors
这将创建一个 Gum Per Invocation 实例。而如果使用@Provides,则相同的 Gum 实例将被传递给两个注入器