副标题:为什么Spring可以解决循环依赖,而你的代码不行?🎯
🎬 开场:可怕的循环依赖
什么是循环依赖?
场景:A依赖B,B依赖A
ServiceA {
@Autowired
private ServiceB serviceB;
}
ServiceB {
@Autowired
private ServiceA serviceA;
}
问题:谁先创建?
创建A → 需要注入B
→ 创建B → 需要注入A
→ 创建A → 需要注入B
→ 创建B → 需要注入A
→ ...
无限循环!💥
真实案例
/**
* 某项目的循环依赖噩梦
*/
@Service
public class OrderService {
@Autowired
private UserService userService; // 需要用户服务
public void createOrder(Long userId) {
User user = userService.getUser(userId);
// 创建订单...
}
}
@Service
public class UserService {
@Autowired
private OrderService orderService; // 需要订单服务
public List<Order> getUserOrders(Long userId) {
return orderService.getOrdersByUserId(userId);
}
}
启动应用:
╔═══════════════════════════════════════╗
║ Error creating bean 'orderService' ║
║ Circular dependency detected! ║
╚═══════════════════════════════════════╝
程序员:???我明明用了@Autowired啊!为什么不行?
📚 循环依赖的三种情况
情况1:构造器循环依赖 ❌ Spring无法解决
/**
* 构造器注入的循环依赖
* Spring无法解决!
*/
@Service
public class ServiceA {
private final ServiceB serviceB;
// 构造器注入
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
// 构造器注入
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
启动结果:
BeanCurrentlyInCreationException:
Error creating bean with name 'serviceA':
Requested bean is currently in creation
原因:
创建A → 调用构造器 → 需要完整的B
→ 创建B → 调用构造器 → 需要完整的A
→ 死锁!❌
情况2:Setter循环依赖 ✅ Spring可以解决
/**
* Setter注入(字段注入)的循环依赖
* Spring可以解决!
*/
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB; // 字段注入
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA; // 字段注入
}
启动结果:✅ 成功!
原因:
Spring的三级缓存机制可以解决!
情况3:Prototype循环依赖 ❌ Spring无法解决
/**
* 原型模式的循环依赖
* Spring无法解决!
*/
@Service
@Scope("prototype") // 原型模式
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Service
@Scope("prototype") // 原型模式
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
启动结果:❌ 报错
原因:
原型Bean每次都要创建新实例,
无法使用缓存,所以无法解决循环依赖
🎯 Spring的三级缓存
三级缓存是什么?
/**
* Spring容器中的三级缓存
*
* 源码位置:DefaultSingletonBeanRegistry
*/
public class DefaultSingletonBeanRegistry {
/**
* 一级缓存:singletonObjects
*
* 存放:完全初始化好的Bean(成品)
*
* 单例池,存放已经完全创建好的Bean
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 二级缓存:earlySingletonObjects
*
* 存放:提前暴露的Bean(半成品)
*
* 早期单例对象,存放实例化但未初始化完成的Bean
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
* 三级缓存:singletonFactories
*
* 存放:创建Bean的工厂(ObjectFactory)
*
* 单例工厂,存放创建Bean的工厂对象
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}
三级缓存的作用
一级缓存(singletonObjects):
- 存放完全初始化好的Bean
- 可以直接使用的Bean
- 最终的归宿
二级缓存(earlySingletonObjects):
- 存放提前暴露的Bean引用
- 解决循环依赖的关键
- 半成品Bean
三级缓存(singletonFactories):
- 存放创建Bean的工厂
- 支持AOP代理
- 延迟创建代理对象
为什么需要三级缓存?
- 一级:存储完整Bean
- 二级:存储半成品Bean,解决循环依赖
- 三级:支持AOP,延迟创建代理对象
🔍 循环依赖解决过程
完整流程图
A依赖B,B依赖A的解决过程:
1. 创建A
├── 实例化A(调用构造器)
├── A对象创建完成(半成品)
├── 将A的ObjectFactory放入三级缓存
├── 填充属性:发现需要注入B
└── 去获取B
│
2. 创建B
├── 实例化B(调用构造器)
├── B对象创建完成(半成品)
├── 将B的ObjectFactory放入三级缓存
├── 填充属性:发现需要注入A
└── 去获取A
│
3. 获取A(从缓存)
├── 一级缓存:没有
├── 二级缓存:没有
├── 三级缓存:有!取出A的ObjectFactory
├── 调用ObjectFactory.getObject()得到A
├── 将A放入二级缓存
├── 删除三级缓存中的A
└── 返回A(半成品)
│
↓
4. B注入A(半成品)
├── B的属性填充完成
├── B初始化完成(@PostConstruct等)
├── B是完整的Bean了
├── 将B放入一级缓存
└── 返回B
│
↓
5. A注入B
├── A的属性填充完成
├── A初始化完成(@PostConstruct等)
├── A是完整的Bean了
├── 将A放入一级缓存
└── 删除二级缓存中的A
完成!A和B都初始化完成,并且互相注入成功!✅
关键源码
/**
* 获取Bean的核心方法
*
* 源码位置:AbstractBeanFactory.doGetBean()
*/
protected <T> T doGetBean(String name, ...) {
// 1. 先从缓存获取(三级缓存查找)
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
// 缓存中有,直接返回
return (T) sharedInstance;
}
// 2. 缓存中没有,开始创建Bean
if (isSingletonCurrentlyInCreation(name)) {
// 正在创建中,说明出现循环依赖
// 从三级缓存获取
}
// 3. 创建Bean实例
sharedInstance = createBean(name, ...);
return (T) sharedInstance;
}
/**
* 从三级缓存获取Bean
*
* 源码位置:DefaultSingletonBeanRegistry.getSingleton()
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 从一级缓存获取(完整的Bean)
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 正在创建中
// 2. 从二级缓存获取(半成品Bean)
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// 双重检查
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 3. 从三级缓存获取(ObjectFactory)
ObjectFactory<?> singletonFactory =
this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用工厂方法获取Bean
singletonObject = singletonFactory.getObject();
// 放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 删除三级缓存
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
/**
* 创建Bean
*
* 源码位置:AbstractAutowireCapableBeanFactory.doCreateBean()
*/
protected Object doCreateBean(String beanName, ...) {
// 1. 实例化Bean(调用构造器)
BeanWrapper instanceWrapper = createBeanInstance(beanName, ...);
Object bean = instanceWrapper.getWrappedInstance();
// 2. 将Bean的ObjectFactory放入三级缓存(提前暴露)
if (isSingletonCurrentlyInCreation(beanName)) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, bean));
}
// 3. 填充属性(依赖注入)
populateBean(beanName, bean, ...);
// 4. 初始化Bean(InitializingBean、@PostConstruct等)
bean = initializeBean(beanName, bean, ...);
return bean;
}
💻 模拟实现
简化版三级缓存
/**
* 简化版的Spring容器(模拟三级缓存)
*/
public class SimpleBeanFactory {
// 一级缓存:完整的Bean
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 二级缓存:半成品Bean
private Map<String, Object> earlySingletonObjects = new HashMap<>();
// 三级缓存:Bean工厂
private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
// 正在创建中的Bean
private Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>());
/**
* 获取Bean
*/
public Object getBean(String beanName) {
// 1. 从缓存获取
Object bean = getSingleton(beanName);
if (bean != null) {
return bean;
}
// 2. 标记为正在创建
singletonsCurrentlyInCreation.add(beanName);
// 3. 创建Bean
bean = createBean(beanName);
// 4. 放入一级缓存
singletonObjects.put(beanName, bean);
// 5. 删除二级和三级缓存
earlySingletonObjects.remove(beanName);
singletonFactories.remove(beanName);
// 6. 标记创建完成
singletonsCurrentlyInCreation.remove(beanName);
return bean;
}
/**
* 从三级缓存获取Bean
*/
private Object getSingleton(String beanName) {
// 一级缓存
Object bean = singletonObjects.get(beanName);
if (bean != null) {
return bean;
}
// 如果正在创建中
if (singletonsCurrentlyInCreation.contains(beanName)) {
// 二级缓存
bean = earlySingletonObjects.get(beanName);
if (bean != null) {
return bean;
}
// 三级缓存
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (factory != null) {
bean = factory.getObject();
// 放入二级缓存
earlySingletonObjects.put(beanName, bean);
// 删除三级缓存
singletonFactories.remove(beanName);
return bean;
}
}
return null;
}
/**
* 创建Bean
*/
private Object createBean(String beanName) {
System.out.println("创建Bean: " + beanName);
// 1. 实例化(调用构造器)
Object bean = instantiate(beanName);
// 2. 提前暴露(放入三级缓存)
ObjectFactory<?> factory = () -> bean;
singletonFactories.put(beanName, factory);
// 3. 填充属性(依赖注入)
populateBean(beanName, bean);
// 4. 初始化
initializeBean(beanName, bean);
return bean;
}
/**
* 实例化Bean
*/
private Object instantiate(String beanName) {
try {
if ("serviceA".equals(beanName)) {
return ServiceA.class.newInstance();
} else if ("serviceB".equals(beanName)) {
return ServiceB.class.newInstance();
}
} catch (Exception e) {
throw new RuntimeException("实例化失败", e);
}
return null;
}
/**
* 填充属性(依赖注入)
*/
private void populateBean(String beanName, Object bean) {
System.out.println("填充属性: " + beanName);
if (bean instanceof ServiceA) {
ServiceA serviceA = (ServiceA) bean;
// 注入ServiceB
serviceA.setServiceB((ServiceB) getBean("serviceB"));
} else if (bean instanceof ServiceB) {
ServiceB serviceB = (ServiceB) bean;
// 注入ServiceA
serviceB.setServiceA((ServiceA) getBean("serviceA"));
}
}
/**
* 初始化Bean
*/
private void initializeBean(String beanName, Object bean) {
System.out.println("初始化Bean: " + beanName);
// @PostConstruct、InitializingBean等
}
}
/**
* 测试类
*/
public class ServiceA {
private ServiceB serviceB;
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
public class ServiceB {
private ServiceA serviceA;
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
/**
* 测试
*/
public class Test {
public static void main(String[] args) {
SimpleBeanFactory factory = new SimpleBeanFactory();
ServiceA serviceA = (ServiceA) factory.getBean("serviceA");
ServiceB serviceB = (ServiceB) factory.getBean("serviceB");
System.out.println("ServiceA: " + serviceA);
System.out.println("ServiceB: " + serviceB);
System.out.println("成功解决循环依赖!");
}
}
/**
* 输出:
* 创建Bean: serviceA
* 填充属性: serviceA
* 创建Bean: serviceB
* 填充属性: serviceB
* 初始化Bean: serviceB
* 初始化Bean: serviceA
* ServiceA: com.example.ServiceA@xxxxx
* ServiceB: com.example.ServiceB@xxxxx
* 成功解决循环依赖!
*/
🎨 循环依赖与AOP
为什么需要三级缓存?
问题:如果只有二级缓存,能解决循环依赖吗?
答案:可以解决,但无法支持AOP!
原因:
两级缓存方案:
一级缓存:完整Bean
二级缓存:半成品Bean(直接存对象)
问题:如果Bean需要AOP代理,什么时候创建代理?
方案1:实例化后立即创建代理
- 问题:所有Bean都要创建代理,浪费资源
- 很多Bean不需要代理
方案2:初始化后创建代理
- 问题:如果有循环依赖,注入的是原始对象,不是代理对象
- 导致AOP失效
三级缓存方案:
一级缓存:完整Bean
二级缓存:半成品Bean(可能是代理)
三级缓存:ObjectFactory(延迟创建代理)
优点:
- 只有在出现循环依赖时,才提前创建代理
- 没有循环依赖时,代理在初始化后创建
- 完美!✅
AOP + 循环依赖示例
/**
* AOP + 循环依赖
*/
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional // 需要AOP代理
public void methodA() {
System.out.println("ServiceA.methodA()");
}
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
public void methodB() {
System.out.println("ServiceB.methodB()");
serviceA.methodA(); // 调用A的方法
}
}
/**
* 创建流程:
*
* 1. 创建ServiceA
* - 实例化ServiceA(原始对象)
* - 放入三级缓存:ObjectFactory(() -> getEarlyBeanReference(serviceA))
* - 填充属性:需要ServiceB
*
* 2. 创建ServiceB
* - 实例化ServiceB(原始对象)
* - 放入三级缓存:ObjectFactory(() -> getEarlyBeanReference(serviceB))
* - 填充属性:需要ServiceA
*
* 3. 从三级缓存获取ServiceA
* - 调用ObjectFactory.getObject()
* - 执行getEarlyBeanReference()
* - 检查ServiceA是否需要AOP代理
* - 需要!创建ServiceA的代理对象
* - 将代理对象放入二级缓存
* - 返回代理对象
*
* 4. ServiceB注入ServiceA的代理对象 ✅
*
* 5. ServiceB初始化完成
*
* 6. ServiceA注入ServiceB
*
* 7. ServiceA初始化
* - 不再创建代理(已经在步骤3创建了)
*
* 结果:
* - ServiceA是代理对象
* - ServiceB持有的serviceA是代理对象
* - AOP生效!✅
*/
关键源码:
/**
* 提前创建AOP代理的关键方法
*
* 源码位置:AbstractAutoProxyCreator.getEarlyBeanReference()
*/
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 记录已经被提前代理的Bean
this.earlyProxyReferences.put(cacheKey, bean);
// 如果需要代理,创建代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
/**
* 正常初始化后的AOP代理创建
*
* 源码位置:AbstractAutoProxyCreator.postProcessAfterInitialization()
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果已经提前创建了代理,不再创建
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
🎯 如何避免循环依赖
方法1:重构代码(推荐)⭐⭐⭐⭐⭐
/**
* ❌ 不好的设计(循环依赖)
*/
@Service
public class OrderService {
@Autowired
private UserService userService;
}
@Service
public class UserService {
@Autowired
private OrderService orderService;
}
/**
* ✅ 好的设计(消除循环依赖)
*
* 方案1:抽取公共服务
*/
@Service
public class OrderService {
@Autowired
private UserService userService;
@Autowired
private OrderQueryService orderQueryService; // 新服务
}
@Service
public class UserService {
@Autowired
private OrderQueryService orderQueryService; // 注入查询服务
}
@Service
public class OrderQueryService {
// 只负责查询,不依赖OrderService和UserService
}
/**
* 方案2:使用事件驱动
*/
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createOrder() {
// 创建订单
Order order = new Order();
// 发布事件,而不是直接调用UserService
eventPublisher.publishEvent(new OrderCreatedEvent(order));
}
}
@Service
public class UserService {
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
// 处理订单创建事件
}
}
方法2:使用@Lazy ⭐⭐⭐⭐
/**
* 使用@Lazy延迟注入
*/
@Service
public class ServiceA {
private final ServiceB serviceB;
// 构造器注入 + @Lazy
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(@Lazy ServiceA serviceA) {
this.serviceA = serviceA;
}
}
/**
* 原理:
* @Lazy会创建一个代理对象
* 只有在真正使用时才会去获取真实的Bean
* 打破了循环依赖的链条
*/
方法3:使用Setter注入 ⭐⭐⭐
/**
* ❌ 构造器注入(Spring无法解决)
*/
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
/**
* ✅ Setter注入(Spring可以解决)
*/
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB; // 字段注入(本质是setter)
}
🎉 总结
核心要点
1. 循环依赖的类型
- 构造器循环依赖:❌ 无法解决
- Setter循环依赖:✅ 可以解决
- Prototype循环依赖:❌ 无法解决
2. 三级缓存
- 一级:singletonObjects(完整Bean)
- 二级:earlySingletonObjects(半成品Bean)
- 三级:singletonFactories(Bean工厂)
3. 解决过程
- 实例化Bean
- 提前暴露(放入三级缓存)
- 填充属性(依赖注入)
- 从缓存获取依赖
- 初始化完成
4. 为什么需要三级缓存?
- 支持AOP代理
- 延迟创建代理
- 只在需要时创建
记忆口诀
循环依赖三级存,
单例对象和工厂。
一级缓存存成品,
完全初始化的Bean。
二级缓存存半成品,
提前暴露来救急。
三级缓存存工厂,
延迟创建AOP代理。
创建Bean先实例化,
ObjectFactory放三级。
填充属性要注入,
从缓存中去获取。
一级二级都没有,
三级工厂来救场。
调用工厂得对象,
放入二级删三级。
注入完成再初始化,
Bean完整放一级。
删除二级和三级,
循环依赖已解决!
构造器注入解决不了,
Setter注入没问题。
原型模式也不行,
单例模式才可以!
愿你的Bean没有循环,依赖永远清晰! 🔄✨