[Spring] 三级缓存解决循环依赖详解

这篇具有很好参考价值的文章主要介绍了[Spring] 三级缓存解决循环依赖详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是循环依赖

注册一个bean对象的过程:
Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果原始对象种的某个方法被AOP了,那么要根据原始对象生成一个代理对象 – 把最终生成的代理对象放入单例池(singletonObjects,也叫一级缓存)中,下次getBea你就直接从单例池拿

循环依赖就是在依赖注入的时候相互注入,如

public class AService{
	@Autowired
	private BService bService;
}
public class BService{
	@Autowired
	private AService aService;
}

三级缓存过程

Spring使用了三级缓存的策略来解决循环依赖问题,过程大致如下
创建AService的bean:
[Spring] 三级缓存解决循环依赖详解,spring,缓存,java
因为暂时还没有BService,所以创建个BService
[Spring] 三级缓存解决循环依赖详解,spring,缓存,java
创建过程中,因为AService已经在三级缓存中出现过,所以会进行以下操作
[Spring] 三级缓存解决循环依赖详解,spring,缓存,java
因为BService的属性都已经赋值了,所以BService的初始化就结束了,可以直接放到一级缓存中,完整过程为:
[Spring] 三级缓存解决循环依赖详解,spring,缓存,java
此时BService已经实例化完成,那么AService中的依赖就可以进行注入了:
[Spring] 三级缓存解决循环依赖详解,spring,缓存,java
完整流程图如下:
[Spring] 三级缓存解决循环依赖详解,spring,缓存,java

简单的源码解析

首先在AbstractAutowireCapabaleBeanFactory类里(我是用ctrl+shift+alt+n找到的)的doCreateBean
先创造了一个bean原始对象,此时还没有依赖注入

		BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        
        Object bean = instanceWrapper.getWrappedInstance();

然后将lambda表达式放入三级缓存中

        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
			//放入三级缓存,这个lambda表达式是为了执行aop生成代理对象用的,如果有aop操作,就会拿到代理对象出来
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

紧接着就是A的依赖填充

	this.populateBean(beanName, mbd, instanceWrapper);

在这个里面会走到一个getSingleton方法,也就是在缓存中找BService

	//allowEarlyReference是是否允许循环依赖
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized(this.singletonObjects) {
                	//一级缓存中找
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                    	//二级缓存中找
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                        	//三级缓存中找
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {	//找到了
                            	//这里相当于上面图文分析中BService在三级缓存中找到AService
                            	//直接用lambda表达式注册,然后把他移动到二级缓存中
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

但是显然AService肯定不会找到,然后就会重新走到createBean,创建一个BService,与A一样走到上述的getSingleton,这时会在三级缓存中找到A,然后注入

填充完成之后就会把BService放到一级缓存中,移除三级缓存中的B,然后结束

	exposedObject = this.initializeBean(beanName, exposedObject, mbd);

执行完整个BService的创建,上面的A的依赖填充才会结束,然后A也执行一遍exposedObject = this.initializeBean(beanName, exposedObject, mbd);这行代码,A也结束。

结合图文演示看代码更容易理解捏文章来源地址https://www.toymoban.com/news/detail-609256.html

到了这里,关于[Spring] 三级缓存解决循环依赖详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring使用三级缓存解决循环依赖?终于完全弄明白了

    文章阅读前推荐 推荐先去看看源码,源码很短,但是对于我们在脑子里构建一个完整思路很重要。看起来非常简单,只需要双击shift,全局查找文件:AbstractAutowireCapableBeanFactory,找到550行左右的doCreateBean方法,重点看一下580行到600行这20行代码就行,包含了三级缓存、属性注

    2024年03月25日
    浏览(30)
  • Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (一)

    循环依赖就是我依赖你、你依赖我,或者A依赖B、B依赖C、C依赖A…组成的错综复杂的依赖关系。 其实各种不同的依赖关系最终从逻辑上都可以演变为:我依赖你、你依赖我。 循环依赖大致可以分为两种情况: 属性依赖:比如A对象有一个属性B,B对象有属性A。 构造器依赖:

    2024年02月11日
    浏览(30)
  • Spring 为什么要用三级缓存来解决循环依赖(AOP),二级缓存不行吗

    解决有代理对象的循环依赖不一定要三级缓存,用二级甚至一级也能解决,下面讨论下Spring为什么选择三级缓存这个方案。 Spring最开始是没有三级缓存的,后面版本因为引入了AOP,有了代理对象,又因为存在循环依赖,为了保证依赖注入过程注入的是代理对象,且不完全打破

    2024年04月26日
    浏览(26)
  • SpringBoot 三级缓存解决循环依赖源码分析

    在 SpringBoot 框架中,如果只存在两级缓存,那么当发生循环依赖的时候可能存在异常的对象创建流程如下图所示: 创建 A 的空白对象 a1 解析填充 A 对象的属性,发现依赖的 B 对象未创建,则触发 B 对象创建 创建 B 对象过程中,填充对象属性时发现依赖 A 对象,此时从缓存中

    2024年02月11日
    浏览(32)
  • Spring三级缓存详解

    Spring三级缓存 是为了解决 对象间的循环依赖 问题。 A依赖B,B依赖A,这就是一个简单的循环依赖。 我们来先看看三级缓存的源码。 (1)查看“获取Bean”的源码,注意getSingleton()方法。 (2)“添加到第1级缓存”的源码: (3)“添加到第3级缓存”的源码: (4)“创建Be

    2024年02月07日
    浏览(42)
  • springIoc依赖注入循环依赖三级缓存

    理论思想,原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理 依赖注入,把对应的属性的值注入到具体的对象中,@autowired,populateBean完成属性的注入 beanFactory,存储对象,使用map结构来存储,在spring中一般存在三级缓存,singleton

    2024年01月16日
    浏览(28)
  • 一文详解Spring Bean循环依赖

    一、背景 有好几次线上发布老应用时,遭遇代码启动报错,具体错误如下: 眨眼一看,这不就是Spring Bean循环依赖报错吗?脑海立马闪过那些年为了进阿里面试时被死亡N连问的场景,那时我们都知道Spring已经支持bean循环依赖,为啥我们的Springboot应用启动时还报这个错误?带

    2024年02月15日
    浏览(20)
  • Spring解决循环依赖

    目录 什么是spring循环依赖 什么情况下循环依赖可以被处理? spring 如何解决循环依赖 创建A这个Bean的流程 答疑 疑问:在给B注入的时候为什么要注入一个代理对象? 初始化的时候是对A对象本身进行初始化,而容器中以及注入到B中的都是代理对象,这样不会有问题吗? 三级

    2024年02月22日
    浏览(35)
  • Spring解决循环依赖问题

    例如,就是A对象依赖了B对象,B对象依赖了A对象。(下面的代码属于 属性的循环依赖 ,也就是初始化阶段的循环依赖,区别与底下 构造器的循环依赖 ) 问题来了: A Bean创建 —— 依赖了 B 属性 ——  触发 B Bean创建 ——  B 依赖了 A 属性 ——  需要 A Bean(但A Bean还在创建

    2024年02月12日
    浏览(27)
  • 【Spring】Spring的循环依赖以及解决方案

    ​ Spring循环依赖指的是两个或多个Bean之间相互依赖,形成一个环状依赖的情况。通俗的说,就是A依赖B,B依赖C,C依赖A,这样就形成了一个循环依赖的环。 ​ Spring循环依赖通常会导致Bean无法正确地被实例化,从而导致应用程序无法正常启动或者出现异常。因此,Spring循环

    2024年04月25日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包