如何创建隐式子注入器作用域Singleton?

时间:2016-12-21 18:30:51

标签: guice

我有以下代码:

import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;

import com.google.inject.*;
import org.junit.jupiter.api.*;

public class GuiceTest {

  public static void main(String[] args) {
    new GuiceTest().test();
  }

  @Test
  public void test() {
    Injector injector = Guice.createInjector();
    MainObject obj1 = injector.getInstance(MainObject.class);
    MainObject obj2 = injector.getInstance(MainObject.class);

    // Ensure two distinct objects.
    assertThat(obj1, is(not(sameInstance(obj2))));

    Dependency dep1 = obj1.getDependency();
    Dependency dep2 = obj2.getDependency();

    for (int i = 0; i < 10; i++) {
      // Ensure only one dependency instance per distinct object
      assertThat(dep1, is(sameInstance(obj1.getDependency())));
      assertThat(dep2, is(sameInstance(obj2.getDependency())));
    }

    // Ensure each object has its own dependency.
    assertThat(dep1, is(not(sameInstance(dep2)))); // fails
  }

  static class ChildModule extends PrivateModule {

    @Override
    protected void configure() {
    }
  }

  static class MainObject {

    private final Injector injector;

    @Inject
    MainObject(Injector injector) {
      this.injector = injector.createChildInjector(new ChildModule());
    }

    Dependency getDependency() {
      return injector.getInstance(Dependency.class);
    }
  }

  @Singleton
  static class Dependency {
  }

}

目标是每Dependency个{(1}} MainObject。这就是为什么我声明它@Singleton并从子注入器调用它。

看起来尽管我使用了儿童注射器,但是单身注册在父母注册中。

我做错了什么?

注意:

  • 这只是完整用例的一个子集。完整用例包含40多个依赖项。
  • 每个依赖项都是可选的,因此我考虑将它们保留在进样器中并通过进样器访问它们。使用injector.getExistingBinding(Key.of(Class))检查它们的存在。
  • 模块可能没有定义依赖项,依赖项需要实现为“隐式”(这样我就可以轻松使用它们而无需在模块中定义它们。)

1 个答案:

答案 0 :(得分:1)

根据 recursive Guice binding-resolution docs,隐式绑定会尽可能在父绑定中创建:

  
      
  1. 使用显式绑定。      
        
    • 如果绑定链接到另一个,请遵循此解析算法。
    •   
    • 如果绑定指定了一个实例,则返回该实例。
    •   
    • 如果绑定指定了提供者,请使用该。
    •   
  2.   
  3. 询问父进样器。如果此进样器具有父进样器,请要求解析绑定。如果成功,请使用它。否则继续。
  4.         

    [...]

         
        
    1. 使用单个@Inject或公共无参数构造函数。      
          
      • 验证所有依赖项的绑定 - 构造函数的参数,以及类型和所有超类型的@Inject方法和字段。
      •   
      • 调用构造函数。
      •   
      • 注入所有字段。在子类型字段之前注入超类型字段。
      •   
      • 注入所有方法。在子类型方法之前注入超类型方法。
      •   
    2.   

docs for createChildInjector加强了这个断言:

  

尽可能在祖先注射器中创建为子注射器创建的即时绑定。这允许在注入器之间共享作用域实例。使用显式绑定可防止与父注入器共享绑定。如果可选的依赖项来自子注入器,则可以静默忽略即时绑定中的可选注入(在父注入器中创建)。

这意味着除非你明确地在子注入器模块中绑定实例或单例(即使它们显式化),否则你将不会有太多的运气保留你正在寻找的单子内部子注入器行为对