📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)、(进阶篇)、(架构篇)清华大学出版社签约作家、Java领域优质创作者、优快云博客专家、阿里云专家博主、51CTO专家博主、产品软文专业写手、技术文章评审老师、技术类问卷调查设计师、幕后大佬社区创始人、开源项目贡献者。
📘拥有多年一线研发和团队管理经验,研究过主流框架的底层源码(Spring、SpringBoot、SpringMVC、SpringCloud、Mybatis、Dubbo、Zookeeper),消息中间件底层架构原理(RabbitMQ、RocketMQ、Kafka)、Redis缓存、MySQL关系型数据库、 ElasticSearch全文搜索、MongoDB非关系型数据库、Apache ShardingSphere分库分表读写分离、设计模式、领域驱动DDD、Kubernetes容器编排等。不定期分享高并发、高可用、高性能、微服务、分布式、海量数据、性能调优、云原生、项目管理、产品思维、技术选型、架构设计、求职面试、副业思维、个人成长等内容。
🌾阅读前,快速浏览目录和章节概览可帮助了解文章结构、内容和作者的重点。了解自己希望从中获得什么样的知识或经验是非常重要的。建议在阅读时做笔记、思考问题、自我提问,以加深理解和吸收知识。阅读结束后,反思和总结所学内容,并尝试应用到现实中,有助于深化理解和应用知识。与朋友或同事分享所读内容,讨论细节并获得反馈,也有助于加深对知识的理解和吸收。💡在这个美好的时刻,笔者不再啰嗦废话,现在毫不拖延地进入文章所要讨论的主题。接下来,我将为大家呈现正文内容。
文章目录
场景设定
假设你开了一家玩具工厂,要组装两种玩具:
- 变形金刚(需要电池)
- 电池(需要装在变形金刚里)
但问题来了:
- 组装变形金刚的时候,需要先把电池装进去
- 生产电池的时候,又需要知道电池要装到哪个变形金刚上
这就像Spring中的两个Bean(变形金刚和电池)互相依赖,必须先有对方才能完成自己。
工厂的三级流水线(对应Spring三级缓存)
工厂为了解决这个问题,设立了三道流水线:
流水线 | 作用 | 对应Spring技术 |
---|---|---|
设计部(三级缓存) | 存玩具的设计图纸(告诉工人怎么组装半成品) | ObjectFactory(生成对象的工厂方法) |
半成品区(二级缓存) | 存组装一半的玩具(比如没装电池的变形金刚) | earlySingletonObjects(早期对象引用) |
成品区(一级缓存) | 存完整的玩具(可以直接卖) | singletonObjects(完整Bean) |
解决问题流程
步骤1:开始组装变形金刚
工人想生产变形金刚,先设计一个「没有电池的变形金刚」图纸(实例化空对象)
把图纸存到设计部(三级缓存),此时:
三级缓存 = { "变形金刚": 生产图纸 }
步骤2:发现需要电池
工人去成品区(一级缓存)找电池 → 无货
启动电池生产线,生成「没装变形金刚的电池」图纸存入设计部(三级缓存):
三级缓存 = {
"变形金刚": 生产图纸,
"电池": 生产图纸
}
步骤3:电池需要变形金刚(重点优化)
电池生产线需要知道电池装到哪个变形金刚上
按顺序检查缓存:
第一站:成品区(一级缓存) → 无变形金刚
第二站:半成品区(二级缓存) → 空(首次生产)
第三站:设计部(三级缓存) → 找到变形金刚图纸
执行图纸生成变形金刚空壳:
空壳特性:
▸ 已实例化但未装电池(未注入属性)
▸ 携带唯一序列号(内存地址固定,如#1234)
关键操作:
存入二级缓存 → { "变形金刚": 空壳#1234 }
移除三级缓存 → { "电池": 生产图纸 }
AOP代理预判:
如果变形金刚需要「隐身模式」(如事务代理):
▸ 直接给空壳#1234披上隐身衣(提前生成代理对象)
▸ 隐身衣的序列号仍是#1234(代理对象地址不变)
步骤4:完成电池生产(补充早期引用说明)
从二级缓存取出变形金刚空壳#1234
电池与空壳建立绑定:
电池通过USB接口写入型号(调用setBatteryType()方法)
此时变形金刚仍是空壳,但序列号#1234已记录在电池中
禁止操作:
▸ ❌ 尝试调用变形金刚.启动引擎()(依赖未注入的电池)
▸ ✅ 允许调用变形金刚.注册电池()(仅需内存写入)
电池完工存入一级缓存:
一级缓存 = { "电池": 成品电池 }
二级缓存保持 = { "变形金刚": 空壳#1234 }
步骤5:完成变形金刚生产(强调引用一致性)
从一级缓存获取电池,将其插入空壳#1234的能源舱(属性注入)
动态升级操作:
如果需添加「自动修复」功能(如日志AOP):
▸ 直接给#1234安装修复模块(后续生成代理)
▸ 序列号仍为#1234(对象地址不变)
执行最终质检(@PostConstruct初始化):
测试变形功能(方法逻辑验证)
充能武器系统(依赖注入后的操作)
缓存状态更新:
一级缓存 = { "电池": 成品电池, "变形金刚": 完整品#1234 }
二级缓存 = 空
早期引用依然有效:
电池内记录的#1234序列号指向升级后的完整品
无需重新插拔电池(对象引用始终一致)
缓存状态跟踪表(全局视角)
步骤 | 一级缓存(成品区) | 二级缓存(半成品区) | 三级缓存(设计部) |
---|---|---|---|
1 | 空 | 空 | 变形金刚图纸 |
2 | 空 | 空 | 变形金刚+电池图纸 |
3 | 空 | 变形金刚空壳 | 电池图纸 |
4 | 电池 | 变形金刚空壳 | 空 |
5 | 电池+变形金刚 | 空 | 空 |
为什么必须三级?
设计图纸(三级缓存):
- 如果直接生产半成品,遇到特殊需求(比如给变形金刚喷漆),后面可能改不动了
- Spring中对应AOP代理:需要延迟生成代理对象,避免类型冲突
半成品区(二级缓存):
- 防止多个工人重复组装半成品(比如同时生产10个变形金刚,不需要10次半成品)
成品区(一级缓存):
- 保证所有人拿到的都是最终版本(避免有的工人拿到半成品,有的拿到成品)
哪些情况工厂解决不了?
-
必须同时组装:如果变形金刚和电池必须同时组装(构造器注入),流水线无法分步操作
-
定制化生产:每次生产新玩具都要从头开始(原型模式Bean)
-
三人互锁:如果「变形金刚→电池→马达→变形金刚」三人循环,流水线可能卡死
一句话总结
Spring的三级缓存就像工厂的流水线分级,通过「先造空壳 → 暂存半成品 → 最后补全」的方式,破解了“先有鸡还是先有蛋”的死循环。
工厂通过「先造壳、再填肉」的策略破解死锁:
- 变形金刚先造空壳 → 让电池能注册信息
- 电池利用空壳完成自己 → 独立存为成品
- 变形金刚用成品电池补全自己 → 最终覆盖空壳
整个过程依赖三级缓存的状态隔离和引用传递机制,确保两个生产线既交叉依赖又互不阻塞。
📥博主的人生感悟和目标
希望各位读者大大多多支持用心写文章的博主,现在时代变了,信息爆炸,酒香也怕巷子深,博主真的需要大家的帮助才能在这片海洋中继续发光发热,所以,赶紧动动你的小手,点波关注❤️,点波赞👍,点波收藏⭐,甚至点波评论✍️,都是对博主最好的支持和鼓励!
- 💂 博客主页: Java程序员廖志伟
- 👉 开源项目:Java程序员廖志伟
- 🌥 哔哩哔哩:Java程序员廖志伟
- 🎏 个人社区:Java程序员廖志伟
- 🔖 个人微信号:
SeniorRD
📙经过多年在优快云创作上千篇文章的经验积累,我已经拥有了不错的写作技巧。同时,我还与清华大学出版社签下了四本书籍的合约,并将陆续出版。这些书籍包括了基础篇、进阶篇、架构篇的📌《Java项目实战—深入理解大型互联网企业通用技术》📌,以及📚《解密程序员的思维密码–沟通、演讲、思考的实践》📚。具体出版计划会根据实际情况进行调整,希望各位读者朋友能够多多支持!
🔔如果您需要转载或者搬运这篇文章的话,非常欢迎您私信我哦~