【发布时间】:2014-03-12 21:30:25
【问题描述】:
假设我们有一个名为 Bean 的类,它依赖于另一个名为 Service 的类,使用 Fields Injection 并且 我们无法更改这些类的代码。另一个类 (App) 使用 Provider 来随时构造 Bean 的新实例,我们可以随意更改这些类中的代码。
由于在Provider 的get() 方法中,新实例是使用new 运算符创建的,因此无法将Service 注入Bean,因此Bean 实例将不完整(服务字段为null)。
绕过该问题的一种方法是在 Provider 中注入 Injector 并在新实例上的 get() 方法中调用 injector.injectMembers()。
代码示例如下(我避免使用接口来缩短代码)。
class Bean {
@Inject private Service service;
public Bean() {
}
public void bar() {
this.service.foo();
}
}
class Service {
public void foo() {
System.out.println("foo");
}
}
class App {
@Inject private Provider<Bean> beanProvider;
public App() {
}
public void run() {
this.beanProvider.get().bar();
}
}
class BeanProvider implements Provider<Bean> {
@Inject Injector injector;
public Bean get() {
Bean mybean = new Bean();
this.injector.injectMembers(mybean);
return mybean;
}
}
// A simple module to bind the classes
class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class);
bind(Bean.class).toProvider(BeanProvider.class);
bind(App.class);
}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule());
injector.getInstance(App.class).run();
}
另一种方法是将 Bean 更改为使用构造注入,但正如我所说,让我们假设我们不能这样做。
我知道大多数人声称应该避免注入 Injector,因为它破坏了整个 DI 理念,因为注入器应该只在应用程序的入口点使用,而不能在其他任何地方使用,但是因为 Guice 提供了不同的方法来在应用程序中使用 DI,例如 Field Injection,可能会发生我描述的情况。此外,我已经看到在几个项目中经常使用字段注入,因此经常会出现这种情况。
那么,有没有一种“更干净”的方法来避免在我描述的问题中注入Injector?
【问题讨论】:
-
在您的示例中,您实际上并不需要
BeanProvider。 Guice 将为您创建一个。所以你可以在没有提供者的情况下只使用bind(Bean.class),你的例子就可以了。还有其他限制吗? -
@condit Bean 的范围比 App 更窄的情况呢? guice (code.google.com/p/google-guice/wiki/InjectingProviders) 的文档建议使用 Provider 来处理此类情况。无论如何,让我们假设使用 Provider 是强制性的。我还需要注射注射器吗?
-
即使这样,Guice 也会自动为您注入一个提供程序,这应该可以解决您的范围问题(因为每个提供程序
get调用都会返回一个新的Bean)。我发现自己唯一一次使用requestInjection是为了 AOP。
标签: java dependency-injection guice guice-3