Guice/DI 和混合注入和运行时传入的参数

Guice / DI and mixing injection and parameters passed in at runtime

我有这样一种情况,当我初始化我的一些 类 时,我需要注入一些字段(例如对工厂的引用等),而其他一些是动态的并在运行时创建(例如用户名ETC)。如何使用 GUICE 框架构建此类对象? 简单地将我需要注入的字段注释为 @Inject 不起作用,因为在使用构造函数创建对象时似乎没有设置它们。例如:

class C {
   @Inject
   private FactoryClass toBeInjected;

   private ConfigurationField passedIn;

   public C(ConfigurationField passedIn) {
      this.passedIn = passedIn;
   }
}

如果我的理解是正确的(我也可能是错的),我通过 new 而不是通过 Guice 创建 C 的新实例这一事实意味着不会进行注入地方。我确实需要在构造函数中传递这些参数,但还需要注入一些字段——那么我该如何解决这个问题?

您正在寻找的是“按需”注射:

public static void main(String[] args) 
{
    Injector injector = Guice.createInjector(...);
    CreditCardProcessor creditCardProcessor = new PayPalCreditCardProcessor();
    injector.injectMembers(creditCardProcessor);
}

或者静态的东西

@Override public void configure() {
   requestStaticInjection(ProcessorFactory.class);
   ...
 }

都解释的很好https://github.com/google/guice/wiki/Injections#on-demand-injection.

注:

Both of these things are code smells and should only really be used for migrating old code over to Guice. New code should not use these approaches.

专门匹配 "mixing injection and parameters passed" 的特征将是 Assisted Injection

class C {
  // Guice will automatically create an implementation of this interface.
  // This can be defined anywhere, but I like putting it in the class itself.
  interface Factory {
    C create(ConfigurationField passedIn);
  }

  @Inject
  private FactoryClass toBeInjected;

  private ConfigurationField passedIn;
  private SomeOtherDepIfYoudLike otherDep;

  @Inject public C(@Assisted ConfigurationField passedIn,
      SomeOtherDepIfYoudLike otherDep) {
    this.passedIn = passedIn;
    this.otherDep = otherDep;
  }
}

现在在您的模块中:

@Override public void configure() {
  install(new FactoryModuleBuilder().build(C.Factory.class));
}

现在当有人想创建一个C时,他们可以避免直接调用构造函数;相反,他们注入一个 C.Factory 并向其中传递他们选择的 ConfigurationField 实例,并接收一个完全构建、完全注入的 C 实例。 (与大多数设计良好的 DI 对象一样,它们 可以 直接调用构造函数。)

请注意,此设计在以下几个方面特别有用:

  • 您可以使用构造函数注入,将所有字段视为最终字段,并将对象视为不可变。
  • 如果您完全坚持使用构造函数注入,您的对象将永远不会处于部分初始化状态,并且您的 API 保持简单(调用构造函数并且您的对象已准备就绪)。
  • 为了测试,您可以编写 C.Factory 的任何实现,并使其 return 成为您想要的任何实例。这可以包括 C 或其工厂的测试替身:您手动或使用 Mockito、EasyMock、JMock 或任何其他模拟框架创建的假货、模拟或间谍。