栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring三级缓存解决循环依赖 源码解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring三级缓存解决循环依赖 源码解析

什么是循环依赖


当我们代码中出现,形如TestA类中依赖注入TestB类,TestB类依赖注入A类时,在IOC过程中creaBean实例化A之后,发现并不能直接initbeanA对象,需要注入B对象,发现对象池里还没有B对象。通过构建函数创建B对象的实例化。又因B对象需要注入A对象,发现对象池里还没有A对象,就会套娃。

什么是三级缓存


三层缓存 singletonFactories 中的泛型是ObjectFactory:是接口,源码上面包含@FunctionInterface,指为函数式接口,仅有一个方法,可以传入lambda表达式,可以是匿名内部类,通过调用getObject方法来执行具体的逻辑。ObjectFactory.getObject() 方法最终会调用getEarlyBeanReference()进行处理,返回创建bean实例化的lambda表达式。
二级缓存 earlySingletonObjects 存放bean,保存半成品bean实例,当对象需要被AOP切面代时,保存代理bean的实例beanProxy
一级缓存(单例池)singletonObjects 存放完整的bean实例

Spring的单例对象的初始化过程

首先我们得清楚Spring的单例对象的初始化,主要分为三步:
1、createBeanInstance: 实例化,也就是在内存中给对象开辟空间
2、populateBean:填充属性
3、initializeBean:调用spring xml中的init() 方法

循环依赖主要发生在第一、第二步。也就是构造器循环依赖和field循环依赖

开始以debug点入源码 beanFactory.preInstantiateSingletons();


这方法开始执行的话说明开始要完成bean的实例化了,将要进行初始化

在doCreateBean的createBeanInstance里进行了bean的实例化,但是还没有进行初始化

首先创建实例化A

Spring首先会创建实例化A,然后会开始尝试填充A中的b属性,首先会从一级缓存也就是单例池中查找,然后会从二级缓存中找,一样找不到,它就会将实例化A放入三级缓存中(此时的实例化A还只是实例化了并没有初始化),因为三级缓存泛型是ObjectFactory,所以能放入。

这里就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。

将A对象放入三级缓存后会实例化B

实例化完B之后一样会从一级缓存中的顺序去找有没有a属性,最后会在三级缓存中找到并没有初始化的A并填充到a属性中。通过缓存的lambda表达式创建A实例对象,并放到二级缓存earlySingletonObjects中

此时B已经实例化并且初始化了

之后会将B对象存放到一级缓存中。但是当有AOP时,B对象还没有存入到一级缓存时,B对象初始化之后需要进行代理对象的创建,此时需要从三级缓存中获取bean实例对象,进行creatProxy创建代理类操作,这时会把proxy和B放入二级缓存中,才会把完整的B对象存入一级缓存中,返回给A对象

再次对A进行初始化

B对象已经完全实例化、初始化完成并存入一级缓存了,这时对象A继续从一级缓存中查询B对象,将会找到并填充到A.b属性中,这时候A里面的b属性有值了,并且是A对象,然后A对象里面继续会有b属性一直循环下去,填充完A.b属性之后会将A对象也存入一级缓存中。

这时候,A、B两对象都已经初始化完成并且都存入一级缓存了,也就创建A、B对象完成了 我的理解

底层会开始从一级缓存开始查,然后查二级缓存,再查三级缓存,在三级缓存中查到了k为a和value为参数为a的getEarlyBeanReference(beanName,mbd,bean)的方法,查到后将a存入二级缓存,然后以b对象开始再进行一次从一级缓存开始查找的操作,然后在二级缓存中找到了a 的半成品,将a 的半成品先当做成品作为b的属性a一起存入一级缓存,存入一级缓存的之后会进行删除b的三级缓存的操作,然后重新对a对象进行初始化,从一级对象中找到b的实例,此时b对象是已经初始化完成的,将b对象赋值为a.b属性,此时能在源码里面看到a里面的b属性是有值的并且是一直循环a和b对象的,然后初始化完成将a存入一级缓存删除所对应的三级缓存之后,a,b就都初始化完成了

对于一级、二级缓存能不能解决循环依赖还有其他的问题等我再研究研究

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/581570.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号