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

时间:2013-02-26 23:04:06

标签: java dependency-injection guice multiple-inheritance

这个问题是 Using guice for a framework with injected classes, proper way to initialize? 的延续,我试图实施,并尝试了其他方法来解决这个问题,但到目前为止还没有任何工作。

主要问题是这个。我有一个InterfaceAInterfaceB,它们在API的不同部分中公开。有两个类实现了这两个接口TestClassRealClass,因此根据我是在测试还是做其他事情,我可以执行以下操作:

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

或者,对于生产:

bind(InterfaceA.class).to(RealClass.class);
bind(InterfaceB.class).to(RealClass.class);

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

  1. 我需要TestClassRealClass的同一个实例绑定InterfaceAInterfaceB的所有注入;所以,就像单身模式一样,除了:
  2. 单例仅适用于特定范围或子注入器,其中许多是在程序执行期间创建的。
  3. 默认的无范围方法会导致为每个接口注入创建多个RealClass / TestClass实例。我不希望这样,所以我尝试使用范围,子注入器和其他方法来实现它。没有任何效果:

    • Child injector approach:我创建了一个新的注入器,并尝试将TestClassRealClass绑定到该注入器中的单例实例。问题是,是否正在使用TestClassRealClass在父注入器和since it's a singleton, it's already instantiated中配置(除非在Stage.DEVELOPMENT中)。例如,在父注入器中无法将InterfaceA绑定到TestClass,然后将其重新绑定为子注入器中的单例。
    • 范围方法:I create a custom scope并注释TestClassRealClass。然后,我进入并退出此范围以获取该范围内的单个实例。问题是我的代码是多线程的,并且从一个线程改变范围会影响全局注入器可以看到的内容,并且会创建其他实例。
    • 组合子进样器和范围方法。我尝试为每个使用此自定义作用域创建一个子注入器,但随后在父项中绑定RealClass失败并带有

      No scope is bound to name.package.WhateverScope.
      

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

    所有这些问题似乎都是由于我需要能够配置是否在父级中使用TestClassRealClass,然后才能够在以后实例化它们,因为单个,用于特定对象组。我正在把头发拉出来完成如何完成!

    顺便说一句,Guice范围的文档很糟糕,几乎无法理解。 This article是唯一能让我到任何地方的人:

1 个答案:

答案 0 :(得分:4)

在发布后不到一个小时就有点突破的道歉。

我似乎能够通过稍微滥用http://code.google.com/p/google-guice/wiki/CustomScopes提供的线程局部范围实现来解决这个问题。在不使用儿童注射器的情况下解决这个问题似乎是一种有点干净的方法。不过,我不确定它是否“合适”。我还会接受其他答案。

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

ThreadLocalScope scope = new ThreadLocalScope();
bindScope(ExperimentScoped.class, scope);
bind(ThreadLocalScope.class).toInstance(scope);

然后,正如文档所说,我需要为范围内播种的每种类型的键绑定一个虚假的提供者:

bind(SomeKey.class)
  .toProvider(ThreadLocalScope.<SomeKey>seededKeyProvider())
  .in(ExperimentScoped.class);
bind(SomeOtherKey.class)
  .toProvider(ThreadLocalScope.<SomeOtherKey>seededKeyProvider())
  .in(ExperimentScoped.class);

我可能还有一些其他可范围的对象,我希望在每个范围内都是不同的,所以我也绑定它们。这些是上面的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);

最后,我可以使用范围从不同的线程并行创建不同的相互依赖的对象集。每个线程都可以执行类似下面的操作,即使它们使用相同的注入器:

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.
}

在我的情况下,我可以完全放弃范围,因为我不关心在正确连接后跟踪范围内的对象集。但是如果我想稍后回到这个范围并注入更多的对象,它可能不会起作用。

希望这有助于某人。 Guice范围文档非常糟糕!