实例化每个范围/组单例 - 陷入Guice依赖地狱

And*_*Mao 6 java dependency-injection multiple-inheritance guice

这个问题是对带有注入类的框架使用guice的延续,正确的初始化方法是什么?我试图实现,并尝试其他方法来解决这个问题,但到目前为止还没有任何工作.

主要问题是这个.我有一个,InterfaceAInterfaceB在API的不同部分公开.有迹象表明,实现这两个接口的两个阶级,TestClassRealClass,让这取决于我是否在测试或做别的事情,我可以做到以下几点:

bind(InterfaceA.class).to(TestClass.class);
bind(InterfaceB.class).to(TestClass.class); 
Run Code Online (Sandbox Code Playgroud)

或者,用于生产:

bind(InterfaceA.class).to(RealClass.class);
bind(InterfaceB.class).to(RealClass.class);
Run Code Online (Sandbox Code Playgroud)

我有两个使用这些类的要求:

  1. 我需要和所有注射相同的实例TestClass或被RealClass约束; 所以,就像单身模式一样,除了:InterfaceAInterfaceB
  2. 单例仅用于特定范围或子注入器,其中许多是在程序执行期间创建的.

默认的无范围方法会导致为每个接口注入创建RealClass/的多个实例TestClass.我不希望这样,所以我尝试使用范围,子注入器和其他方法来实现它.没有任何效果:

  • 儿童注射方法:我创建了一个新的注射器,并尝试结合TestClassRealClass以单一实例在该注射器.问题是,是否TestClassRealClass正在使用中的父喷射器构造,并且因为它是一个单件,它已经被实例化(除非Stage.DEVELOPMENT).例如,InterfaceA无法TestClass在父注入器中绑定到它,然后将其重新绑定为子注入器中的单例.
  • 范围方法:我创建一个自定义范围和注释TestClassRealClass.然后,我进入并退出此范围以获取该范围内的单个实例.问题是我的代码是多线程的,并且从一个线程改变范围会影响全局注入器可以看到的内容并且创建其他实例.
  • 结合儿童注射器和范围方法.我尝试为每个使用此自定义作用域创建子注入器,但随后RealClass在父作业中绑定失败

    No scope is bound to name.package.WhateverScope.
    
    Run Code Online (Sandbox Code Playgroud)

    因为它似乎坚持认为它始终WhateverScope可用,而不仅仅是在儿童注射器中.

所有这些问题似乎都是由于我需要能够配置是否在父级中使用TestClass或者RealClass在父级中,然后能够稍后将它们实例化为特定的一组对象的单例.我正在把头发拉出来完成如何完成!

顺便说一句,Guice范围的文档很糟糕,几乎无法理解.这篇文章是唯一让我在任何地方的文章:

And*_*Mao 5

抱歉,发布后不到一个小时就取得了突破。

我似乎能够通过稍微滥用http://code.google.com/p/google-guice/wiki/CustomScopes提供的线程本地范围实现来解决此问题。这似乎是不使用子注入器即可解决此问题的一种较干净的方法。不过,我不确定它是否正确。我仍然会接受其他答案。

这就是我所做的。首先,创建一个作用域实例,将其绑定到适当的注释,并使其在注射器中可用:

ThreadLocalScope scope = new ThreadLocalScope();
bindScope(ExperimentScoped.class, scope);
bind(ThreadLocalScope.class).toInstance(scope);
Run Code Online (Sandbox Code Playgroud)

然后,如文档所述,我需要为将在范围内播种的每种类型的密钥绑定一个伪造的提供程序:

bind(SomeKey.class)
  .toProvider(ThreadLocalScope.<SomeKey>seededKeyProvider())
  .in(ExperimentScoped.class);
bind(SomeOtherKey.class)
  .toProvider(ThreadLocalScope.<SomeOtherKey>seededKeyProvider())
  .in(ExperimentScoped.class);
Run Code Online (Sandbox Code Playgroud)

我可能还希望在每个作用域中区分一些其他可作用域的对象,因此我也将它们绑定在一起。这些是TestClassRealClass以上。可能还有SomeScopedClass用注释的@ExperimentScoped

bind(InterfaceA.class).to(TestClass.class).in(ExperimentScoped.class);
bind(InterfaceB.class).to(TestClass.class).in(ExperimentScoped.class);

bind(SomeInterface.class).to(SomeScopedClass.class);
Run Code Online (Sandbox Code Playgroud)

最后,我可以使用作用域从不同的线程并行创建不同的相互依赖的对象集。每个线程即使使用相同的注入器,也可以执行以下操作:

ThreadLocalScope scope = injector.getInstance(ThreadLocalScope.class);      
scope.enter();

try {
    // Seed the seed-able keys
    scope.seed(SomeKey.class, keyInstance);
    scope.seed(SomeOtherKey.class, otherKeyInstance);    

    SomeScopedClass instance = injector.getInstance(SomeScopedClass.class);

    // Hooray! instance was injected with the seeds and created just for this scope!
}
finally {
    scope.exit(); // Throws away the scope and referenced objects.
}
Run Code Online (Sandbox Code Playgroud)

就我而言,我可以完全放弃该范围,因为一旦它们正确连接后,我就不在乎跟踪范围内的对象集。但是,如果我想稍后再回到此范围并注入更多对象,则可能无法正常工作。

希望这对某人有所帮助。Guice范围界定文档太糟糕了!