当前位置: 代码网 > it编程>编程语言>Java > Spring三级缓存解决循环依赖的解析过程

Spring三级缓存解决循环依赖的解析过程

2025年05月05日 Java 我要评论
一、循环依赖场景假设存在两个bean的相互依赖:@componentpublic class servicea { @autowired private serviceb serviceb

一、循环依赖场景

假设存在两个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放入singletonobjects

4. 回溯完成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监控 singletonobjectsearlysingletonobjects 的比例

总结

spring的三级缓存机制通过 提前暴露对象引用 + 动态代理生成 的协同设计,在保证单例性的前提下,优雅地解决了循环依赖问题。理解该机制需要重点把握bean生命周期的阶段划分和缓存状态的转换逻辑。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com