使用 Guice 在所有对象中注入实例
Inject instance in all objects using Guice
class A {
public A() {
}
}
class B {
@Inject
@Named("A")
private A a;
public B() {
}
public A getA() {
return a;
}
}
class AModule extends AbstractModule {
@Override
protected void configure() {
}
@Provides
@Singleton
@Named("A")
public A providesA() {
return new A();
}
}
我们是这样做的:
AModule module = new AModule();
Injector injector = Guice.createInjector(module);
B b = injector.getInstance(B.class);
System.out.println(sample.getA());
但是我们有很多 类 以 A 作为依赖项,我们不想在每次创建实例时都添加此代码。
那么,有什么方法可以在创建 B 的实例时自动注入 A 的实例吗?
创建与您在问题中建议的一样多的顶级注入器(通常)是不正确的。注入器的创建是昂贵的,一旦 Guice 计算了你的依赖图,你应该不需要重新计算它。一般来说,您的应用程序中应该有一个顶级注入器,任何其他注入器要么是 "child injectors" 要么是单独且不相关的对象图的一部分。
从"worst"到"best"的顺序:
保持喷油器静止
如果您要将 DI 引入大量现有或遗留代码中,那么将注入器隐藏到可公开访问的对象中可能很诱人。
public class InjectorHolder() {
private InjectorHolder() {} // Not instantiable
private static Injector injector;
public static void initializeInjector() {
injector = Guice.createInjector(new AModule(), new BModule(), andSoOn());
}
public static Injector get() {
return injector;
}
public static B getB() {
return injector.getInstance(B.class);
}
}
此时您可以从到目前为止已迁移的应用程序部分调用 InjectorHolder.get().getInstance(B.class)
或 InjectorHolder.getB()
。请注意,这可能很难测试,并且直接依赖于整个应用程序中的 Guice——这两者都不理想。
使用 Guice 静态注入
Guice 提供 a few features for static injection, notably the method call requestStaticInjection(Class... types)
。通过在您的模块中调用它,Guice 将在创建注入器后立即注入具有 @Inject
注释的静态成员。
public class StaticBModule extends AbstractModule() {
@Override public void configure() { requestStaticInjection(BFactory.class); }
}
public class BFactory() {
@Inject @Named("B") private static Provider<B> bProvider;
public B get() {
return bProvider.get();
}
}
现在您可以调用 new BFactory().get()
而不是 new B()
,并且它们都将转到同一个注入器。当然,如果您将 static Provider<A>
放入 B
class 并为此请求静态注入,您也可以允许 new B()
代替,或者您可以保留 BFactory
作为一个实例,并在测试期间替换它以发出您需要的 B
个实例。到那时,您还不如改造调用 new BFactory()
的 classes 以包含 static Provider<B>
,并让它们静态注入,然后迁移它们,一直到你有一个完整的 DI 解决方案(下面解释)。
你也可以参考this SO question,里面有例子
理想方案
您向我们展示了 A
和 B
,但可能其他一些 class C
使用了 B
的许多实例,也许 YourApplication
(其中包含您的静态 main
方法)使用 C
。您可以使用 Guice 创建 YourApplication
或 C
的实例,然后 C
可以包含注入的 Provider<B> bFactory
。然后,您可以调用 bFactory.get()
来创建您可能需要的 B
个实例,而不是调用 new B()
。
这样,您的 classes 完全取决于它们所依赖的对象,除了在顶层之外没有静态或对 Guice 的引用。
class A {
public A() {
}
}
class B {
@Inject
@Named("A")
private A a;
public B() {
}
public A getA() {
return a;
}
}
class AModule extends AbstractModule {
@Override
protected void configure() {
}
@Provides
@Singleton
@Named("A")
public A providesA() {
return new A();
}
}
我们是这样做的:
AModule module = new AModule();
Injector injector = Guice.createInjector(module);
B b = injector.getInstance(B.class);
System.out.println(sample.getA());
但是我们有很多 类 以 A 作为依赖项,我们不想在每次创建实例时都添加此代码。
那么,有什么方法可以在创建 B 的实例时自动注入 A 的实例吗?
创建与您在问题中建议的一样多的顶级注入器(通常)是不正确的。注入器的创建是昂贵的,一旦 Guice 计算了你的依赖图,你应该不需要重新计算它。一般来说,您的应用程序中应该有一个顶级注入器,任何其他注入器要么是 "child injectors" 要么是单独且不相关的对象图的一部分。
从"worst"到"best"的顺序:
保持喷油器静止
如果您要将 DI 引入大量现有或遗留代码中,那么将注入器隐藏到可公开访问的对象中可能很诱人。
public class InjectorHolder() {
private InjectorHolder() {} // Not instantiable
private static Injector injector;
public static void initializeInjector() {
injector = Guice.createInjector(new AModule(), new BModule(), andSoOn());
}
public static Injector get() {
return injector;
}
public static B getB() {
return injector.getInstance(B.class);
}
}
此时您可以从到目前为止已迁移的应用程序部分调用 InjectorHolder.get().getInstance(B.class)
或 InjectorHolder.getB()
。请注意,这可能很难测试,并且直接依赖于整个应用程序中的 Guice——这两者都不理想。
使用 Guice 静态注入
Guice 提供 a few features for static injection, notably the method call requestStaticInjection(Class... types)
。通过在您的模块中调用它,Guice 将在创建注入器后立即注入具有 @Inject
注释的静态成员。
public class StaticBModule extends AbstractModule() {
@Override public void configure() { requestStaticInjection(BFactory.class); }
}
public class BFactory() {
@Inject @Named("B") private static Provider<B> bProvider;
public B get() {
return bProvider.get();
}
}
现在您可以调用 new BFactory().get()
而不是 new B()
,并且它们都将转到同一个注入器。当然,如果您将 static Provider<A>
放入 B
class 并为此请求静态注入,您也可以允许 new B()
代替,或者您可以保留 BFactory
作为一个实例,并在测试期间替换它以发出您需要的 B
个实例。到那时,您还不如改造调用 new BFactory()
的 classes 以包含 static Provider<B>
,并让它们静态注入,然后迁移它们,一直到你有一个完整的 DI 解决方案(下面解释)。
你也可以参考this SO question,里面有例子
理想方案
您向我们展示了 A
和 B
,但可能其他一些 class C
使用了 B
的许多实例,也许 YourApplication
(其中包含您的静态 main
方法)使用 C
。您可以使用 Guice 创建 YourApplication
或 C
的实例,然后 C
可以包含注入的 Provider<B> bFactory
。然后,您可以调用 bFactory.get()
来创建您可能需要的 B
个实例,而不是调用 new B()
。
这样,您的 classes 完全取决于它们所依赖的对象,除了在顶层之外没有静态或对 Guice 的引用。