为什么使用@Autowired不会导致循环依赖,而构造函数的自动布线却会?

问题描述 投票:0回答:1

我注意到在我正在做的一个应用程序中出现了一个奇怪的错误。在修改一个类的时候,我把一堆属性移到构造函数中自动装配,而不是使用字段注入,然而,这导致我在启动时得到一个错误,因为有一个循环依赖。下面是导致错误的依赖关系的分解。

  • 我试图使用 ServiceA 里面 TargetClass.
  • ServiceAServiceB 通过其构造函数注入
  • ServiceBServiceC 现场注射
  • ServiceCTargetClass 现场注射

我正在寻找重构的方法,或者尝试将一些逻辑移到更好的地方,这样我就可以消除这种循环依赖,然而,我很好奇为什么用两种不同的方法来注入 ServiceA 导致两种不同的结果。

如果我注射 ServiceA 通过现场注入,只是用 @Autowired 在场上,我的应用程序启动得很好。然而,如果我切换到 TargetClass 使用构造函数注入,我会得到一个关于循环依赖的错误。

Spring处理这两种类型的注入的方式有什么不同,导致一种在这种情况下失败,而另一种则可以工作?

spring spring-boot dependency-injection
1个回答
1
投票

字段注入的工作原理是这样的

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);
© www.soinside.com 2019 - 2024. All rights reserved.