【问题标题】:Inject instance in all objects using Guice使用 Guice 在所有对象中注入实例
【发布时间】:2016-02-26 03:09:06
【问题描述】:
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 的实例?

【问题讨论】:

  • 我想避免这样的代码:AModule module = new AModule(); Injector injector = Guice.createInjector(module); B b = injector.getInstance(B.class); 如果我可以使用自动注入创建 B 的实例,那就太好了。
  • 这就是我的问题。有什么办法吗?
  • 我的理想代码是:AModule module = new AModule(); Injector injector = Guice.createInjector(module); injector.injectNamedSomething(); ,然后B b = new B(); b.getA();,因为我已经使用了命名注入器。
  • 我的实例创建者代码不应该担心注入器,因为我已经定义了一次。
  • 在您的示例代码中,A “自动注入”,因为它有一个零参数构造函数。您能否提供有关您所面临的确切问题的更多详细信息?

标签: java dependency-injection guice


【解决方案1】:

按照您在问题中的建议创建尽可能多的顶级注入器(通常)是不正确的。创建注入器的成本很高,一旦 Guice 计算了依赖关系图,您就不需要重新计算它了。通常,您的应用程序中应该有一个顶级 Injector,而任何其他 Injector 要么是“子注入器”,要么是单独且不相关的对象图的一部分。

从“最差”到“最好”的顺序:

保持注入器静态

如果您将 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(),它们都会进入同一个注入器。当然,如果您将static Provider&lt;A&gt; 放入您的B 类并为此请求静态注入,您也可以允许new B(),或者您可以将您的BFactory 作为一个实例并在测试期间替换它以发出B 您需要的实例。到那时,您不妨改造调用new BFactory() 的类,改为包含static Provider&lt;B&gt;,并让它们静态注入,然后迁移它们,一直到您拥有完整的DI 解决方案(如下所述) )。

你也可以咨询this SO question,里面有例子。

理想的解决方案

您已经向我们展示了AB,但大概其他一些类C 使用了B 的许多实例,并且可能YourApplication(其中包含您的静态main 方法)使用@987654345 @。您可以使用 Guice 创建YourApplicationC 的实例,然后C 可以包含注入的Provider&lt;B&gt; bFactory。然后,您可以调用bFactory.get() 来创建尽可能多的B 实例,而不是调用new B()

这样,您的类完全依赖于它们所依赖的内容,除了顶层之外没有静态或对 Guice 的引用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 2011-06-21
    相关资源
    最近更新 更多