一、循环依赖场景
假设存在两个bean的相互依赖:
@component
public class servicea {
@autowired
private serviceb serviceb;
}
@component
public class serviceb {
@autowired
private servicea servicea;
}二、三级缓存定义
在 defaultsingletonbeanregistry 中定义:
// 一级缓存:完整bean(k:bean名称 v:实例化+初始化完成的bean) private final map<string, object> singletonobjects = new concurrenthashmap<>(256); // 二级缓存:早期暴露对象(k:bean名称 v:未完成属性注入的原始bean) private final map<string, object> earlysingletonobjects = new hashmap<>(16); // 三级缓存:对象工厂(k:bean名称 v:objectfactory) private final map<string, objectfactory<?>> singletonfactories = new hashmap<>(16);
三、解决流程(以servicea和serviceb为例)
1. 创建servicea
sequencediagram
participant container
participant cache1 as singletonobjects
participant cache2 as earlysingletonobjects
participant cache3 as singletonfactories
container->>cache1: 检查servicea是否存在
cache1-->>container: 不存在
container->>container: 实例化servicea(构造器调用)
container->>cache3: 添加servicea的objectfactory
container->>container: 开始属性注入(需要serviceb)关键代码段:
// abstractautowirecapablebeanfactory#docreatebean addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean));
2. 发现需要serviceb
sequencediagram
participant container
participant cache1
participant cache2
participant cache3
container->>cache1: 检查serviceb是否存在
cache1-->>container: 不存在
container->>container: 实例化serviceb(构造器调用)
container->>cache3: 添加serviceb的objectfactory
container->>container: 开始属性注入(需要servicea)3. 解决serviceb对servicea的依赖
sequencediagram
participant container
participant cache1
participant cache2
participant cache3
container->>cache1: 查找servicea
cache1-->>container: 不存在
container->>cache2: 查找servicea
cache2-->>container: 不存在
container->>cache3: 获取servicea的objectfactory
container->>container: 执行getearlybeanreference()
container->>cache2: 将生成的代理对象存入earlysingletonobjects
container->>serviceb: 注入servicea的早期引用
container->>container: 完成serviceb初始化
container->>cache1: 将serviceb放入singletonobjects4. 回溯完成servicea初始化
sequencediagram
participant container
participant cache1
participant cache2
participant cache3
container->>servicea: 注入已初始化的serviceb
container->>container: 执行servicea的初始化后方法
container->>cache1: 将servicea放入singletonobjects
container->>cache2: 移除servicea的早期引用
container->>cache3: 移除servicea的objectfactory四、关键机制详解
1. getearlybeanreference() 的核心作用
protected object getearlybeanreference(string beanname, rootbeandefinition mbd, object bean) {
// 如果有必要,在此处生成代理对象
if (!mbd.issynthetic() && hasinstantiationawarebeanpostprocessors()) {
for (beanpostprocessor bp : getbeanpostprocessors()) {
if (bp instanceof smartinstantiationawarebeanpostprocessor) {
smartinstantiationawarebeanpostprocessor ibp =
(smartinstantiationawarebeanpostprocessor) bp;
bean = ibp.getearlybeanreference(exposedobject, beanname);
}
}
}
return bean;
}2. 三级缓存必要性分析
| 缓存级别 | 解决的问题 | 典型场景 |
|---|---|---|
| singletonfactories | 处理aop代理的延迟生成 | 需要保证代理对象的单例性 |
| earlysingletonobjects | 避免重复创建早期引用 | 多个bean依赖同一个未完成初始化的bean |
| singletonobjects | 存储最终可用bean | 正常bean获取 |
五、设计约束与限制
1.仅支持单例作用域
原型(prototype)作用域的bean无法解决循环依赖,因为spring不缓存原型bean
2.构造器注入限制
如果循环依赖通过构造器注入发生,无法解决(实例化前就需要完成依赖注入)
3.异步初始化风险
使用@async等方法增强的bean可能破坏初始化顺序
六、调试技巧
查看缓存状态
在 defaultsingletonbeanregistry 类中设置断点:
// 查看三级缓存内容
system.out.println("singletonfactories: " + singletonfactories.keyset());
system.out.println("earlysingletonobjects: " + earlysingletonobjects.keyset());
system.out.println("singletonobjects: " + singletonobjects.keyset());强制抛出循环依赖异常
在配置类添加:
@bean
public circularreferencesbean circularreferencesbean() {
return new circularreferencesbean(circularreferencesbean());
}七、性能优化建议
避免过度使用循环依赖
即使技术可行,也应通过设计模式(如事件驱动)解耦
合理使用@lazy注解
延迟加载非必要依赖:
@autowired @lazy private serviceb serviceb;
监控缓存命中率
通过jmx监控 singletonobjects 与 earlysingletonobjects 的比例
总结
spring的三级缓存机制通过 提前暴露对象引用 + 动态代理生成 的协同设计,在保证单例性的前提下,优雅地解决了循环依赖问题。理解该机制需要重点把握bean生命周期的阶段划分和缓存状态的转换逻辑。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论