什么是循环依赖,Spring是如何解决的,为什么要使用三级缓存来解决,二级缓存不能吗

您所在的位置:网站首页 三级缓存解决循环依赖问题的过程是怎样的 什么是循环依赖,Spring是如何解决的,为什么要使用三级缓存来解决,二级缓存不能吗

什么是循环依赖,Spring是如何解决的,为什么要使用三级缓存来解决,二级缓存不能吗

2024-07-12 13:00| 来源: 网络整理| 查看: 265

关于源码好多文章都写了源码,而且源码还是要看视频学着去看才可能看的懂,这里就不贴了,主要是简介明了的说一下循环依赖以及Spring中是如何解决的。

什么是循环依赖

大家了解过套娃没,挺类似的,不过这个是A套B,B又套A,死循环了,所以就有了循环依赖的问题。 在创建A的时候发现A中的属性需要B对象,那就先去创建B对象,又发现B中的属性需要A对象,那又去创建A,形成死循环,这就是循环依赖。

在了解Spring解决循环依赖问题之前,需要了解注入属性的方式、Spring中的三级缓存、bean的创建过程。

关于注入属性的方式

上面说到创建A时B属性的注入,如果是构造方法去注入,那循环依赖问题没有方法解决,如果是Set方法注入,那就可以使用三级缓存来解决,Spring中就是这样的解决的。

Bean的大致创建过程

实例化—设置属性—初始化

Spring中的三个缓存是什么

一级缓存:singletonObjects,存放初始化后的单例对象 二级缓存:earlySingletonObjects,存放实例化,未完成初始化的单例对象(未完成属性注入的对象) 三级缓存:singletonFactories,存放ObjectFactory对象 都是Map集合 单例对象先实例化存在于singletonFactories中,后存在于earlySingletonObjects中,最后初始化完成后放入singletonObjects中**。

Spring是如何解决循环依赖问题的?

上面说到Spring是使用三级缓存(Map)解决的循环依赖问题,那具体是怎么做的,看下面的步骤。 假设A依赖B,B依赖A,Spring创建A实例的过程如下:

1、A依次执行doGetBean方法、依次查询三个缓存是否存在该bean、没有就createBean,实例化完成(早期引用,未完成属性装配),放入三级缓存中,接着执行populateBean方法装配属性,但是发现装配的属性是B对象,走下面步骤。

2、创建B实例,依次执行doGetBean、查询三个缓存、createBean创建实例,接着执行populateBean发现属性中需要A对象。

3、再次调用doGetBean创建A实例,查询三个缓存,在三级缓存singletonFactories得到了A的早期引用(在第一步的时候创建出来了),将它放到二级缓存并移除3级缓存并返回,B完成属性装配,一个完整的对象放到一级缓存singletonObjects中。

4、B完成之后就回到A了,A得到完整的B,肯定也完成全部初始化,也存入一级缓存中。 解决了循环依赖问题。这里可能很多初学者很蒙,什么是早期引用,其实学过C语言的指针的话就比较好理解了,这里的引用就是地址,所以先开辟内存而不封装属性,我后面再给它封装属性,那引用得到的永远是这个地址的最新值,所以就可以先给引用地址后面再封装属性值,这个一定要与传值区分开来,单纯的传值和传地址是不一样的

为什么不使用二级缓存?

如果仅仅是解决循环依赖问题,二级缓存也可以,但是如果注入的对象实现了AOP,那么注入到其他bean的时候,不是最终的代理对象,而是原始的。通过三级缓存的ObjectFactory才能实现类最终的代理对象。

一级缓存能不能解决循环依赖问题?

可以解决,但是因为初始化完成和未初始化完成的都放在这个map中,拿到的可能是没有完成初始化的,属性都是空的,直接空指针异常。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3