Java Guice和;“范围”;单身汉

Java Guice和;“范围”;单身汉,java,dependency-injection,guice,Java,Dependency Injection,Guice,我试图学习Guice,但下面的场景似乎很难。假设我有A、B和C类。我应该能够做到以下几点(注意,这个例子在某种程度上简化为实际情况): A是全局单例 A依赖于供应商B(即工厂) B依赖于A和供应商C(即工厂) C依赖于A和B 当B创建C时,C的依赖项B必须是同一个实例,即从C的角度来看,B是单例的 我尝试过创建儿童注射器: private static class MainModule extends AbstractModule{ @Override protected vo

我试图学习Guice,但下面的场景似乎很难。假设我有A、B和C类。我应该能够做到以下几点(注意,这个例子在某种程度上简化为实际情况):

  • A是全局单例
  • A依赖于供应商B(即工厂)
  • B依赖于A和供应商C(即工厂)
  • C依赖于A和B
  • 当B创建C时,C的依赖项B必须是同一个实例,即从C的角度来看,B是单例的

    我尝试过创建儿童注射器:

    private static class MainModule extends AbstractModule{
    
        @Override
        protected void configure() {
            bind(A.class).in(Singleton.class);
        }
    
        @Provides
        B createB(Injector injector){
            return injector.createChildInjector(new SubModule()).getInstance(B.class);
        }
    }
    
    private static class SubModule extends AbstractModule{
    
        @Override
        protected void configure() {
            bind(B.class).in(Singleton.class);
            bind(C.class);
        }
    }
    
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new MainModule());
    
        A a = injector.getInstance(A.class);
    
        B b1 = a.getB();
        B b2 = a.getB();
    
        // all following C's are different instances
        C b1c1 = b1.getC(); //this has b1 and a
        C b1c2 = b1.getC(); //this has b1 and a
    
        C b2c1 = b2.getC(); //this has b2 and a
        C b2c2 = b2.getC(); //this has b2 and a
    
    }

    但是Guice给出了B已经绑定的错误(MainModule中提供了方法)。因此,我需要覆盖MainModule的B绑定,但这似乎不可能使用子注入器

    该问题可以通过使用多个喷油器来解决,例如,为createB方法创建一个新喷油器,并将喷油器A作为参数,但使用多个喷油器似乎不是最佳做法


    编辑:在C实例中添加注释,以澄清它们应该具有哪个B实例

    我将发布此作为一个答案,它更像是解决方案,而不是完整的解决方案,但对于我的应用程序来说可能已经足够好了:

    private static class MainModule extends AbstractModule{
    
        @Override
        protected void configure() {
            bind(A.class).in(Singleton.class);
            bind(SubModule.class).in(Singleton.class);
        }
    
        @Provides
        B createB(Injector injector){
            SubModule m = injector.getInstance(SubModule.class);
            return Guice.createInjector(m).getInstance(B.class);
        }
    }
    
    private static class SubModule extends AbstractModule{
    
        private final A a;
    
        @Inject
        public SubModule(A a) {
            this.a = a;
        }
    
        @Override
        protected void configure() {
            bind(A.class).toInstance(a);
            bind(B.class).in(Singleton.class);
            bind(C.class);
        }
    }
    
    首先,我认为大多数绑定都在main模块中,但我想如果它们只在B的上下文中使用(并像我在A中那样路由其他绑定),那么它们无论如何都可以移动到子模块。这与链接问题的答案大致相似: 但我创建了新的顶级注入器,因为我似乎无法在两个模块中绑定B,否则我可能会错过一些东西


    (第一次这样做,不确定这是否是正确的方法,将一个变通方法作为自己的答案发布)

    是否有一个原因,主模块和子模块不能同时安装到初始注入器中,或者您不能用
    @Singleton
    注释
    @提供了createB(…)
    ?嗯,可能我有点不清楚,如果我说,对于B的每个依赖项,B都被认为是单例的,但是其他地方可能有多个B,也就是说,每次调用A.getB时,它都返回一个新实例,这是否更清楚。如果我用@Singleton注释createB,我想B在任何地方都会被视为单例。我还可以注意到父注入器到目前为止只有单例绑定(这里是A,在实际应用中更多),因此我可以用父注入器创建子模块,注入每个单例,再次将它们作为单例绑定,并在创建B之前创建全新的顶级注入器,但我希望避免再次编写它们。您可能希望研究辅助注入器。因此,与其使用
    B
    提供程序,不如使用
    CFactory
    ,并将其称为
    工厂。创建(此)
    。您的问题是否与“”相关?