Guice中辅助注入的循环依赖

时间:2013-12-13 17:48:04

标签: dependency-injection guice

我正在使用Guice进行辅助注射。这是一个标准方案:

Class TargetType {

   @Inject
   TargetType(@Assisted Param1 assistedParam, InjectedType injectedType) 
   {
      /* ... */
   }
}

Class InjectedType {

   @Inject
   injectedType(OtherInjectedType otherInjectedType) 
   {
      /* ... */
   }
}

现在我可以使用Guice工厂来调用TargetTypeFactory.create(assistedArg /* instanceof Param1 */),并愉快地获取我的TargetType实例,其中InjectedType的实例由Guice注入。

我的问题是:如果我希望InjectedType引用正在创建的TargetType的实例,该怎么办?换句话说,我想:

Class TargetType {

   @Inject
   TargetType(@Assisted Param1 assistedParam, InjectedType injectedType) 
   {

   }
}

Class InjectedType {

   @Inject
   injectedType(/* How to get this? -> */  TargetType constructedTargetType, OtherInjectedType otherInjectedType) 
   {

   }
}

我当前的解决方法非常难看:我在没有TargetType的情况下手动创建InjectedType,然后我使用InjectedTypeFactory获取InjectedType实例并调用{{1} } setInjectedType(InjectedType)实例上的方法。 Ungh!

1 个答案:

答案 0 :(得分:1)

有趣的问题。我不认为有一个完全干净的解决方案,但也许这种基于儿童注射器的解决方案将适合您:

首先,创建一个自定义guice绑定注释供您自己使用:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface JamrozikParam {}

然后,将TargetType更改为如下所示:

class TargetType {

   @Inject
   TargetType(@JamrozikParam Param1 assistedParam, InjectedType injectedType) 
   {

   }
}

保持InjectedType原样。

现在,您将获得TargetType的实例:

Injector topInjector = Guice.createInjector(/* Your modules here */);
// Note that the modules used there can't mention TargetType or InjectedType
// Now many lines later
Param1 myP1val;
myP1val = // ... however that was computed
Injector childInjector = topInjector.childInjector(new Param1Module(myP1val));
TargetType t1 = childInjector.getInstance(TargetType.class);

Param1Module是一个类似于以下的类:

public class Param1Module extends AbstractModule {
  private final Param1 p1val;
  public Param1Module(Param1 p1val) {this.p1val = p1val;}
  protected void configure() {
    bind(Param1.class).annotatedWith(JamrozikParam.class).toInstance(p1val);
    bind(TargetType.class).in(Singleton.class);
    bind(InjectedType.class).in(Singleton.class);
  }
}

请注意,为了使其工作,Guice将创建一个代理来解决循环依赖。我建议您更轻松地创建代理,并使InjectedType实现一个接口,让TargetType注入该接口而不是直接注入InjectedType,然后将该接口绑定到{{1 }}。否则,guice将不得不做一些可怕的字节码重写,而这只是在寻找麻烦。


我强烈建议您查看整个问题并重构事情,这样您就不需要这样做了。也许你的两个对象不需要在构造函数中相互了解?例如,您可以通过浏览一些主管对象将它们作为方法参数传递给彼此:

InjectedType