什么是Spring的循环依赖

Spring 的循环依赖是 Spring IoC 容器中一个比较常见的问题。理解循环依赖及其解决方案对于掌握 Spring 的高级特性非常重要。
什么是循环依赖?
循环依赖是指在 Spring 容器中,两个或多个 Bean 互相依赖对方,导致在初始化过程中无法正常完成依赖注入。循环依赖通常发生在构造函数注入或 setter 方法注入时。
实际场景
假设我们有两个服务:ServiceA 和 ServiceB。ServiceA 依赖于 ServiceB,而 ServiceB 也依赖于 ServiceA。这种相互依赖就形成了循环依赖。
代码示例
定义 ServiceA 和 ServiceB:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void doSomething() {
System.out.println("ServiceA is doing something...");
serviceB.doSomething();
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doSomething() {
System.out.println("ServiceB is doing something...");
serviceA.doSomething();
}
}
循环依赖的问题
在上面的代码中,ServiceA 和 ServiceB 互相依赖对方。Spring 容器在初始化时会遇到以下问题:
-
初始化 ServiceA:
- Spring 尝试创建
ServiceA的实例。 ServiceA的构造函数需要ServiceB的实例。- Spring 尝试创建
ServiceB的实例。
- Spring 尝试创建
-
初始化 ServiceB:
- Spring 尝试创建
ServiceB的实例。 ServiceB的构造函数需要ServiceA的实例。- 但是
ServiceA的实例尚未完全创建,因为ServiceB的依赖还没有注入。
- Spring 尝试创建
-
死锁:
- Spring 容器无法完成
ServiceA和ServiceB的初始化,因为它们互相依赖,形成了一个死锁。
- Spring 容器无法完成
Spring 如何处理循环依赖
Spring 提供了几种方式来处理循环依赖问题:
- 使用 setter 方法注入(推荐)
- 如果使用 setter 方法注入,Spring 可以在初始化 Bean 时先注入一个引用,从而避免循环依赖。
- 修改代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void doSomething() {
System.out.println("ServiceA is doing something...");
serviceB.doSomething();
}
}
@Service
public class ServiceB {
private ServiceA serviceA;
@Autowired
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doSomething() {
System.out.println("ServiceB is doing something...");
serviceA.doSomething();
}
}
- 使用
@Lazy注解- 如果使用构造函数注入,可以通过
@Lazy注解延迟 Bean 的初始化,从而解决循环依赖问题。 - 修改代码如下:
- 如果使用构造函数注入,可以通过
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
public void doSomething() {
System.out.println("ServiceA is doing something...");
serviceB.doSomething();
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(@Lazy ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doSomething() {
System.out.println("ServiceB is doing something...");
serviceA.doSomething();
}
}
总结
循环依赖是指在 Spring 容器中,两个或多个 Bean 互相依赖对方,导致在初始化过程中无法正常完成依赖注入。Spring 提供了以下几种方式来处理循环依赖:
- 使用 setter 方法注入:这是推荐的方式,因为 Spring 可以在初始化 Bean 时先注入一个引用。
- 使用
@Lazy注解:如果使用构造函数注入,可以通过@Lazy注解延迟 Bean 的初始化,从而解决循环依赖问题。
理解循环依赖及其解决方案对于掌握 Spring 的高级特性非常重要。

3841

被折叠的 条评论
为什么被折叠?



