Dependency injection 在Guice中使用辅助注入的循环依赖

Dependency injection 在Guice中使用辅助注入的循环依赖,dependency-injection,guice,Dependency Injection,Guice,我正在使用Guice进行辅助注射。以下是一个标准场景: 类TargetType{ @注入 TargetType(@assistedParam1 assistedParam,InjectedType InjectedType) { /* ... */ } } 类注入类型{ @注入 injectedType(其他injectedType其他injectedType) { /* ... */ } } 现在,我可以使用Guice factory调用TargetTypeFactory.create(as

我正在使用Guice进行辅助注射。以下是一个标准场景:

类TargetType{
@注入
TargetType(@assistedParam1 assistedParam,InjectedType InjectedType)
{
/* ... */
}
}
类注入类型{
@注入
injectedType(其他injectedType其他injectedType)
{
/* ... */
}
}
现在,我可以使用Guice factory调用
TargetTypeFactory.create(assistedArg/*instanceof Param1*/)
并愉快地获得我的
TargetType
实例以及Guice注入的
InjectedType
实例

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

类TargetType{
@注入
TargetType(@assistedParam1 assistedParam,InjectedType InjectedType)
{
}
}
类注入类型{
@注入
injectedType(/*如何获取?->*/TargetType constructedTargetType,OtherInjectedType OtherInjectedType)
{
}
}

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

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

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

@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
,然后将该接口绑定到
InjectedType
。否则,guice将不得不用字节码动态重写来做一些可怕的事情,这只是自找麻烦


我强烈建议您考虑一下您的整个问题,重构一些东西,这样您就不需要这样做了。也许您的两个对象不需要在其构造函数中相互了解?例如,您可以通过查看一些监控对象,将它们作为方法参数相互传递:

class TargetType {

   @Inject
   TargetType(@Assisted Param1 assistedParam) 
   {

   }

   void ttMethod1(InjectedType injected, String other) { }
   // other methods
}

class InjectedType {

   @Inject
   injectedType(OtherInjectedType otherInjectedType) 
   {

   }

   void injMethod1(TargetType constructedTarget, String other) { }
   // other methods
}

class TargetTypeSupervisor {
  private TargetType target;
  private InjectedType injected;

  @Inject TargetTypeSupervisor(@Assisted Param1 assistedParam, InjectedType injected) {
    this.injected = injected;
    this.target = new Target(assistedParam);
  }

  void ttMethod1(String other) { target.ttMethod1(injected, other); }
  void injMethod1(String other) { injected.injMethod1(target, other); }
  // other methods as needed
}

我真的怀疑这是可能的,特别是考虑到您引入了循环依赖,所以Guice还应该创建一个代理对象。不过,我可能错了。忘了Guice吧,如果手动调用构造函数,你会怎么做?我希望Guice会在幕后为我实例化一个代理对象,正如这里所解释的:当然我自己不会创建这样的代理,太多的样板代码了。谢谢你的全面回答!我的解决方案类似于您的
主管
:我的
TargetType
有一个
setInjectedType
方法,该方法在手动编码的
TargetType工厂
的构造函数中调用,紧跟在
TargetType
构造函数之后调用。我在任何地方都使用接口,但为了简单起见,这里省略了它们。我知道injector解决方案要求我在获得
myP1val
后创建子injector,这需要在执行我的一些应用程序逻辑后调用Guice。因此,我将继续使用手动工厂解决方案。再次感谢!:)