Guice @Provides 方法与提供者 类
Guice @Provides Methods vs Provider Classes
我正在处理一个相当大的项目,其中有很多注入。我们目前正在使用 class 实现 Provider
每次需要一次的注入,它们大多只有一行 get
方法。
每次我需要一个新的供应商时,都要创建一个新的 class 开始变得烦人。在我的 Module
中使用提供者 classes 而不是 @Provides
方法有什么好处,反之亦然?
据我所知,对于大多数简单的情况,它们是完全等价的。
/**
* 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>
,即使密钥绑定到 class 或实例。如果直接获取实例,Guice 会自动调用 get
,如果实例不存在,则会创建一个隐式的 Provider<Foo>
。绑定注释适用于两种样式。
@Provides 的主要优点是紧凑,尤其是与匿名内部 Provider 实现相比。但是请注意,在某些情况下您可能希望支持 Provider classes:
您可以创建自己的长寿命 Provider 实例,可能带有构造函数参数,并将键绑定到这些实例而不是 class 文字。
bind(Foo.class).toProvider(new FooProvisioner("bar", "baz"));
如果您使用的是与 JSR 330 (javax.inject) 兼容的框架,您可以轻松绑定到 javax.inject.Provider classes 或实例。 com.google.inject.Provider 扩展了该接口。
bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
您的提供程序可能很复杂,可以考虑到它自己的 class。根据您构建测试的方式,以这种方式测试您的 Provider 可能更容易。
提供商可以扩展抽象 classes。使用@Provides 方法执行此操作可能并不容易或不直观。
您可以将多个key直接绑定到同一个Provider上。每个 @Provides 方法只生成一个绑定,尽管您可以将其他键绑定到 key(此处为 @Quux Foo)并让 Guice 进行第二次查找。
如果您想(例如)在不使用 Guice 作用域或绑定的情况下缓存或记忆实例,提供程序很容易装饰或包装。
bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
重要:尽管对于 Guice 无法创建的 classes 来说,这是一个很好的策略,但请记住,Guice 可以自动创建并注入一个 Provider<T>
用于您以任何方式 bind
的任何 T,包括 class 名称、密钥或实例。除非涉及您自己的实际逻辑,否则无需创建显式提供程序。
类 的实例化方式也有所不同。
例如:
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 实例。
而如果使用@Provides,相同的 Gum 实例将被传递给两个 Injectors
我正在处理一个相当大的项目,其中有很多注入。我们目前正在使用 class 实现 Provider
每次需要一次的注入,它们大多只有一行 get
方法。
每次我需要一个新的供应商时,都要创建一个新的 class 开始变得烦人。在我的 Module
中使用提供者 classes 而不是 @Provides
方法有什么好处,反之亦然?
据我所知,对于大多数简单的情况,它们是完全等价的。
/**
* 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>
,即使密钥绑定到 class 或实例。如果直接获取实例,Guice 会自动调用 get
,如果实例不存在,则会创建一个隐式的 Provider<Foo>
。绑定注释适用于两种样式。
@Provides 的主要优点是紧凑,尤其是与匿名内部 Provider 实现相比。但是请注意,在某些情况下您可能希望支持 Provider classes:
您可以创建自己的长寿命 Provider 实例,可能带有构造函数参数,并将键绑定到这些实例而不是 class 文字。
bind(Foo.class).toProvider(new FooProvisioner("bar", "baz"));
如果您使用的是与 JSR 330 (javax.inject) 兼容的框架,您可以轻松绑定到 javax.inject.Provider classes 或实例。 com.google.inject.Provider 扩展了该接口。
bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
您的提供程序可能很复杂,可以考虑到它自己的 class。根据您构建测试的方式,以这种方式测试您的 Provider 可能更容易。
提供商可以扩展抽象 classes。使用@Provides 方法执行此操作可能并不容易或不直观。
您可以将多个key直接绑定到同一个Provider上。每个 @Provides 方法只生成一个绑定,尽管您可以将其他键绑定到 key(此处为 @Quux Foo)并让 Guice 进行第二次查找。
如果您想(例如)在不使用 Guice 作用域或绑定的情况下缓存或记忆实例,提供程序很容易装饰或包装。
bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
重要:尽管对于 Guice 无法创建的 classes 来说,这是一个很好的策略,但请记住,Guice 可以自动创建并注入一个 Provider<T>
用于您以任何方式 bind
的任何 T,包括 class 名称、密钥或实例。除非涉及您自己的实际逻辑,否则无需创建显式提供程序。
类 的实例化方式也有所不同。 例如:
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 实例。 而如果使用@Provides,相同的 Gum 实例将被传递给两个 Injectors