我注意到在我正在做的一个应用程序中出现了一个奇怪的错误。在修改一个类的时候,我把一堆属性移到构造函数中自动装配,而不是使用字段注入,然而,这导致我在启动时得到一个错误,因为有一个循环依赖。下面是导致错误的依赖关系的分解。
ServiceA
里面 TargetClass
.ServiceA
已 ServiceB
通过其构造函数注入ServiceB
有 ServiceC
现场注射ServiceC
有 TargetClass
现场注射我正在寻找重构的方法,或者尝试将一些逻辑移到更好的地方,这样我就可以消除这种循环依赖,然而,我很好奇为什么用两种不同的方法来注入 ServiceA
导致两种不同的结果。
如果我注射 ServiceA
通过现场注入,只是用 @Autowired
在场上,我的应用程序启动得很好。然而,如果我切换到 TargetClass
使用构造函数注入,我会得到一个关于循环依赖的错误。
Spring处理这两种类型的注入的方式有什么不同,导致一种在这种情况下失败,而另一种则可以工作?
字段注入的工作原理是这样的
ServiceA serviceA = new ServiceA();
ServiceB serviceB = new ServiceB();
serviceA.serviceB = serviceB;
serviceB.serviceA = serviceA;
构造函数注入失败,因为
ServiceA serviceA = new ServiceA(????); // Cannot inject serviceB because to create serviceB I need serviceA which is being constructed
不过,即使是使用构造函数,也有办法实现循环deps。
class ServiceA {
javax.inject.Provider<ServiceB> serviceBProvider;
@Autowired ServiceA(javax.inject.Provider<ServiceB> serviceBProvider) {
this.serviceBProvider = serviceBProvider;
}
void later() {
this.serviceBProvider.get().methodOfServiceB();
}
void methodOfServiceA() {}
}
class ServiceB {
javax.inject.Provider<ServiceA> serviceAProvider;
@Autowired ServiceB(javax.inject.Provider<ServiceA> serviceAProvider) {
this.serviceAProvider = serviceAProvider;
}
void later() {
this.serviceAProvider.get().methodOfServiceA();
}
void methodOfServiceB() {}
}
因为Spring也有这样的功能
Provider<ServiceA> serviceAProvider = new Provider<>();
Provider<ServiceB> serviceBProvider = new Provider<>();
ServiceA serviceA = new ServiceA(serviceBProvider);
ServiceB serviceB = new ServiceB(serviceAProvider);
serviceAProvider.set(serviceA);
serviceBProvider.set(serviceB);