spring三级缓存,解决循环依赖问题
总结
spring支持只有setter注入的singleton的循环依赖。其他不支持。
循环依赖的两种情况
- 构造器循环依赖
- setter注入的循环依赖
也分为
- singleton 支持循环依赖
- prototype 不支持循环依赖
@Score是IOC容器的作用域 ;singleton 单实例的;prototype 多实例的(每次获取Bean的时候会有一个新的实例);reqeust 每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前。
三级缓存的内容:
第一级缓存:也叫单例池,存放已经经历了完整生命周期的Bean对象。
第二级缓存:存放早期暴露出来的Bean对象,实例化以后,就把对象放到这个Map中。(Bean可能只经过实例化,属性还未填充)。
第三级缓存:存放早期暴露的Bean的工厂。
A依赖B,B依赖A
1、A创建过程中需要B,于是先将A放到三级缓存,去实例化B。
2、B实例化的过程中发现需要A,于是B先查一级缓存寻找A,如果没有,再查二级缓存,如果还没有,再查三级缓存,找到了A,然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A。
3、B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中的状态)。然后回来接着创建A,此时B已经创建结束,可以直接从一级缓存里面拿到B,去完成A的创建,并将A放到一级缓存。
简单总结
三级缓存分别是
- 存储完整对象的singletonObjects,
- 存储半成品对象的earlySingletonObjects,
- 存储对象的创建工厂的singletonFactories。
完成对象,半成品对象,工厂对象
当出现循环依赖时,Spring 会从 完成品 和 半成品 缓存中获取已经创建的对象,如果都没获取到,会调用 工厂 中的 ObjectFactory 来创建半成品对象。在半成品对象创建完成之后,将其注入到之前创建的 Bean 中,完成循环依赖的解决。
prototype的场景
构造器
setter注入
不支持循环依赖的原因
(BoyFriend)applicationContext.getBean("boyFriend") -> AbstractBeanFactory#doGetBean() -> isPropertypeCurrentlyInCreation(beanName) 为true, 则是发生了递归,则直接抛出异常。
解决循环依赖的关键,就是单例的三级缓存。
单例是唯一的,所以三级缓存不能支持prototype。
singleton的循环依赖
AbstractAutowireCapableBeanFactory#doCreateBean ->
- setter方法用: addSingletonFactory() 将属性还没有被赋值的bean实例放到三级缓存里。 -> popluateBean()循环给属性赋值 ->
- 构造器用:
执行了autowireConstructor();
这里会存已经加载的节点列表,如果有重复的则直接报循环引用。
开发时的解决办法
1.
@Lazy
https://www.jb51.net/article/221554.htm
2.从代码层面解决,引用规范一下,从根本解决。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)