使用Guice在所有对象中注入实例

时间:2016-02-25 10:25:05

标签: java dependency-injection 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的实例?

1 个答案:

答案 0 :(得分:2)

创建与您在问题中建议的顶级注射器一样(通常)不正确。注入器创建很昂贵,一旦Guice计算了依赖关系图,您就不需要再次计算它。一般来说,您的应用程序中应该有一个顶级注射器,而任何其他注射器都是"儿童注射器"或者是一个单独的和不相关的对象图的一部分。

从最差"顺序来看最好的":

静态保持注射器

如果要将DI引入许多现有代码或遗留代码中,那么将Injector存储到可公开访问的对象中可能很诱人。

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,特别是方法调用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(),并且它会全部转到同一个注射器。当然,如果您将new B()放入static Provider<A>类并为此请求静态注入,或者您可以将B保留为实例,则也可以允许BFactory并在测试期间替换它以发出所需的B个实例。此时,您可能只需要改进调用new BFactory()而不是包含static Provider<B>的类,并让它们静态注入,然后将它们迁移,直到您有完整的DI解决方案(如下所述)。

您也可以咨询this SO question,其中有一个例子。

理想的解决方案

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

通过这种方式,您的类完全取决于它们所依赖的内容,没有静态或对Guice的引用,而不是顶层。