使用 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,里面有例子

理想方案

您向我们展示了 AB,但可能其他一些 class C 使用了 B 的许多实例,也许 YourApplication(其中包含您的静态 main 方法)使用 C。您可以使用 Guice 创建 YourApplicationC 的实例,然后 C 可以包含注入的 Provider<B> bFactory。然后,您可以调用 bFactory.get() 来创建您可能需要的 B 个实例,而不是调用 new B()

这样,您的 classes 完全取决于它们所依赖的对象,除了在顶层之外没有静态或对 Guice 的引用。