Spring三级缓存的数据结构是什么
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
一、核心前置说明
Spring的三级缓存定义在 DefaultSingletonBeanRegistry 类中,是解决单例Bean循环依赖、保证Bean创建线程安全的核心机制。三级缓存本质均为线程安全的Map集合,但键值类型、存储对象、使用场景完全不同,底层依托 ConcurrentHashMap 实现高并发读写,兼顾线程安全与性能。
三级缓存的Key统一为Bean名称(String类型),仅Value类型存在差异,这是Spring缓存查找、替换、销毁的核心依据。
二、三级缓存逐层级数据结构拆解
1. 一级缓存:singletonObjects(成品单例池)
数据结构:private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256)
泛型定义:Key = String(Bean的唯一名称),Value = Object(完整初始化的单例Bean实例)
核心特性:
- 存储已完成实例化、属性填充、初始化(init-method/PostProcessor)的成熟Bean,是Spring对外提供Bean的最终数据源
- 一旦Bean存入一级缓存,后续所有获取Bean的操作都会直接命中该缓存,无需重复创建
- 容量初始值256,采用ConcurrentHashMap保证多线程下的安全读写,无锁化设计提升并发性能
2. 二级缓存:earlySingletonObjects(早期半成品缓存)
数据结构:private final Map<String, Object> earlySingletonObjects = new HashMap<>(16)
泛型定义:Key = String(Bean的唯一名称),Value = Object(仅完成实例化、未完成属性填充的早期Bean实例)
核心特性:
- 存储无AOP增强的早期Bean,仅用于循环依赖场景下的临时暴露
- 底层为HashMap(非线程安全),因为Spring通过singletonObjects锁(一级缓存锁)控制并发,无需额外线程安全保障
- 当Bean完全初始化后,二级缓存中的数据会被移除,最终数据沉淀到一级缓存
3. 三级缓存:singletonFactories(工厂缓存)
数据结构:private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16)
泛型定义:Key = String(Bean的唯一名称),Value = ObjectFactory<?>(Bean工厂函数式接口,用于生成Bean实例)
核心特性:
- 三级缓存是解决AOP循环依赖的关键,Value并非Bean实例,而是延迟创建Bean的工厂对象
- ObjectFactory是函数式接口,仅含 getObject() 方法,调用时才会生成Bean(含AOP代理对象)
- Bean实例化后立即存入三级缓存,属性填充阶段若触发循环依赖,会通过工厂生成早期Bean,并存入二级缓存
- 同样采用HashMap,由singletonObjects锁保证并发安全,初始化完成后清空当前Bean的三级缓存数据
三、三级缓存数据结构对比总结
一级缓存 | singletonObjects | ConcurrentHashMap | 完整Bean实例 | 对外提供最终单例Bean |
二级缓存 | earlySingletonObjects | HashMap | 早期半成品Bean(无AOP) | 普通循环依赖临时存储 |
三级缓存 | singletonFactories | HashMap | ObjectFactory<?>工厂对象 | 解决AOP代理循环依赖 |
四、关键设计细节补充
- 三级缓存的查找优先级:一级缓存 > 二级缓存 > 三级缓存,逐级查找保证Bean获取效率
- singletonObjects采用ConcurrentHashMap,是因为一级缓存是全局共享的最终数据源,必须支持高并发安全访问
- 二、三级缓存用HashMap,是因为Spring通过singletonObject锁(同一时间仅一个线程创建Bean)规避并发问题,兼顾性能与内存开销
- 三级缓存的工厂模式,实现了Bean实例化与AOP代理的解耦,避免循环依赖时提前创建代理导致的逻辑异常
- 无循环依赖场景下,Bean实例化后仍会放入三级缓存:这是Spring的固定创建流程,并非只有循环依赖才会触发三级缓存存放。Bean完成实例化后,会无条件加入三级缓存;若无循环依赖,整个属性填充、初始化阶段不会调用三级缓存的ObjectFactory工厂,也就不会生成早期Bean、不会用到二级缓存;待Bean完全初始化并迁入一级缓存后,Spring会主动清理当前Bean对应的三级缓存数据,避免内存冗余。
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
本专栏聚焦Spring全生态体系,从IoC/AOP核心原理入手,覆盖Spring Boot自动配置、事务管理、Web开发等实战内容。拆解循环依赖、动态代理等高频面试难点,助力开发者从入门到精通,打通单体到微服务的技术链路,解决企业级开发痛点,提升架构设计与问题排查能力,成为Java后端进阶的必备技术专栏。

查看13道真题和解析