spring三级缓存,解决循环依赖问题

 


总结

spring支持只有setter注入的singleton的循环依赖。其他不支持。

 

循环依赖的两种情况

  1. 构造器循环依赖
  2. setter注入的循环依赖

也分为

  1. singleton 支持循环依赖
  2. 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.从代码层面解决,引用规范一下,从根本解决。

 

posted @   CodingOneTheWay  阅读(221)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
回到顶部
点击右上角即可分享
微信分享提示