Spring三级缓存解密:循环依赖破局之道

一、循环依赖的致命困境

1.1 典型场景示例

@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}

传统初始化流程

  1. 创建ServiceA实例 → 需要注入ServiceB
  2. 创建ServiceB实例 → 需要注入ServiceA
  3. 回到步骤1 → 无限循环

二、三级缓存架构揭秘

2.1 缓存层次结构


缓存层级存储内容生命周期阶段
一级缓存完全初始化好的单例Bean初始化完成
二级缓存完成实例化但未初始化的原始Bean属性填充前
三级缓存Bean的ObjectFactory(工厂对象)实例化后立即存入

三、缓存操作核心流程

3.1 Bean创建流程图解


四、源码级执行分析

4.1 关键方法调用链

// AbstractBeanFactory.doGetBean()
↓ getSingleton(beanName, true) // 尝试从缓存获取
  ↓ getSingleton(beanName, () -> createBean(...)) 
    ↓ createBean() 
      ↓ doCreateBean()
        ↓ addSingletonFactory(beanName, () -> getEarlyBeanReference(...)) // 存入三级缓存
        ↓ populateBean() // 属性注入触发依赖查找

4.2 缓存交互时序

// 首次获取ServiceA
1. getSingleton("serviceA") → null
2. createBean() → 实例化ServiceA
3. addSingletonFactory("serviceA", ObjectFactory)
4. populateBean() → 发现需要serviceB

// 获取ServiceB
5. getSingleton("serviceB") → null
6. createBean() → 实例化ServiceB
7. addSingletonFactory("serviceB", ObjectFactory)
8. populateBean() → 发现需要serviceA

// 再次获取ServiceA
9. getSingleton("serviceA") → 从三级缓存获取ObjectFactory
10. getEarlyBeanReference() → 返回原始对象或代理对象
11. 将serviceA引用存入二级缓存

五、AOP代理的特殊处理

5.1 代理对象生成时机

// AbstractAutowireCapableBeanFactory
protected Object getEarlyBeanReference(String beanName, 
                                      RootBeanDefinition mbd, 
                                      Object bean) {
    // 如果存在SmartInstantiationAwareBeanPostProcessor
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = 
                (SmartInstantiationAwareBeanPostProcessor) bp;
            return ibp.getEarlyBeanReference(exposedObject, beanName);
        }
    }
    return exposedObject;
}

关键点

  • 三级缓存存储的是ObjectFactory而非原始对象
  • AOP代理在此阶段提前生成
  • 保证最终注入的是同一个代理对象

六、缓存策略的局限性

6.1 无法解决的场景

场景类型示例解决方案
构造器循环依赖new ServiceA(serviceB)使用@Lazy延迟注入
prototype作用域@Scope("prototype")重构代码设计
异步初始化@Async初始化方法调整初始化顺序
非单例Bean非Spring管理的对象保证依赖项为单例

6.2 典型异常分析

// 构造器注入导致的异常信息
BeanCurrentlyInCreationException: 
Error creating bean with name 'serviceA': 
Requested bean is currently in creation: 
Is there an unresolvable circular reference?

破局方案

// 使用@Lazy注解打破循环
public ServiceA(@Lazy ServiceB serviceB) {
    this.serviceB = serviceB;
}

七、生产环境调优建议

7.1 缓存配置参数

# 允许早期引用暴露(默认true)
spring.main.allow-circular-references=true 

# 单例缓存最大数量(默认无限制)
spring.beans.singleton.max-count=10000

7.2 性能监控指标

// 监控缓存命中率
DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) ctx.getBeanFactory();
int singletonCount = registry.getSingletonCount();
int earlySingletonCount = registry.getEarlySingletonReferences().size();

八、现代架构演进

8.1 与Spring Boot的整合


8.2 响应式编程的影响

// Reactor上下文中的延迟注入
@Bean
public ServiceA serviceA(ObjectProvider<ServiceB> serviceBProvider) {
    return new ServiceA(serviceBProvider.getIfAvailable());
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值