Dependency injection 在Guice中使用辅助注入的循环依赖
我正在使用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
类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。因此,我将继续使用手动工厂解决方案。再次感谢!:)