【发布时间】:2015-03-27 23:31:46
【问题描述】:
我正在从事一个相当大的项目,该项目有很多注入。我们目前正在使用一个类,该类为每个需要注入的注入实现 Provider,并且它们大多有一行 get 方法。
每当我需要一个新的提供者时,创建一个新类就开始变得烦人了。在我的 Module 中使用提供程序类而不是 @Provides 方法有什么好处,反之亦然?
【问题讨论】:
标签: java dependency-injection guice roboguice
我正在从事一个相当大的项目,该项目有很多注入。我们目前正在使用一个类,该类为每个需要注入的注入实现 Provider,并且它们大多有一行 get 方法。
每当我需要一个新的提供者时,创建一个新类就开始变得烦人了。在我的 Module 中使用提供程序类而不是 @Provides 方法有什么好处,反之亦然?
【问题讨论】:
标签: java dependency-injection guice roboguice
类的实例化方式也有所不同。 例如:
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());
}
}
这将创建一个 Gum Per Invocation 实例。 而如果使用@Provides,相同的 Gum 实例将被传递给两个注入器
【讨论】:
据我所知,它们对于大多数简单的情况都是完全等价的。
/**
* 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 */ }
}
无论是哪种风格,Guice 都允许您注入Foo 和Provider<Foo>,即使键绑定到类或实例。如果直接获取实例,Guice 会自动调用get,如果不存在,则创建隐式Provider<Foo>。绑定注解在这两种样式中都有效。
@Provides 的主要优点是紧凑,特别是与匿名内部 Provider 实现相比。但是请注意,在某些情况下,您可能希望使用 Provider 类:
您可以创建自己的长期存在的 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 方法只生成一个绑定,尽管您可以将其他键绑定到 key(此处为@Quux Foo)并让 Guice 进行第二次查找。
如果您想(例如)在不使用 Guice 范围或绑定的情况下缓存或记忆实例,则提供者很容易装饰或包装。
bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
重要提示:尽管对于 Guice 无法创建的类来说这是一个很好的策略,但请记住,Guice 可以为您 bind 中的任何 T 自动创建和注入 Provider<T>任何方式,包括类名、键或实例。除非涉及到您自己的实际逻辑,否则无需创建显式提供程序。
【讨论】: