什么是循环依赖?就是两个Bean相互引用,比如用@Autowire 相互注入。
 
那么Spring是如何解决这个问题的呢?在Bean还未完全实例化前(类只实例化了一部分),将bean提前暴露出来,可以被其他Bean引用。
 
源码解析:
 
问题1:什么情况下需要提前暴露?
 
Spring托管的bean是通过getBean()-->doCreateBean()创建的。
 
正常情况下,单例模式,第一次调用getBean单例初始化完成后,直接放入cache了,后面再次调用直接从cache拿,不用走doCreateBean 了。
 
0
 
 
当有循环依赖时候,第二次调用getBean代码earlySingletonExposure就会=true,那么
就会触发行提前暴露bean的逻辑。
 
关键代码:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 
AbstractAutowireCapableBeanFactory.doCreateBean();
 
0
 
 
 
问题2: 提前暴露出去的对象是指定类型的Bean的实例本身吗?
不是的,是一个ObjectFactory用于创建该Bean实例 。因为Spring AOP机制,bean在后续实例化过程中可能会被BeanPostProcess处理,生成一个Proxy对象。
 
问题3: 是怎么提前暴露出去的?
其实很简单,遍历所有的BeanPostProcessor ,看是不是SmartInstantiationAwareBeanPostProcessor 对象(该接口是Spring AOP的顶级接口),不是(不需要AOP)直接返回原始bean。SmartInstantiationAwareBeanPostProcessor 提供了一个后门getEarlyBeanReference,该方法提前先调用了proxy bean的生成方法 wrapIfNecessary(),也就是说,AOP提前切入了。
0
 
 
问题4: 提前暴露出去的bean和最终生成的bean是同一个吗?
SmartInstantiationAwareBeanPostProcessor 接口做了强制规定,要么是同一个proxy对象,要么直接放回原始bean(不需要AOP的类)。
0
 
下面用AbstractAutoProxyCreator这个具体实现类的代码作进一步说明。 方法postProcessAfterInitialization() 加了一个判断,如果之前调用了getEarlyBeanReference(),完成了AOP,这里就不重复调用wrapIfNecessary()了(只是从earlyProxyReferences 做了remove),从而保证是同一个proxy对象。
0
 
 
问题5:很多文档说的循环依赖是通过三级缓存解决的,这个说法是咋回事?
 
上面详细介绍了singletonFactories 怎么暴露出去的,三级缓存就是DefaultSingletonBeanRegistry类里面的三个map,缓存核心逻辑见下段代码,先找singletonObjects,找不到再从earlySingletonObjects找,还是没有直接用singletonFactories 工厂创建(里面对singletonObjects加了锁,防止并发错误)。
0
 
代码实践:
为了证明以上说法,我们简单写一点代码加以验证。
代码:https://gitee.com/zfj321/spring-sourcecode-study
然后在下面位置打一个断点,进行跟踪。
0
 
 
参考资料:
 
 
 
 

Spring循环依赖的问题的更多相关文章

  1. spring循环依赖问题分析

    新搞了一个单点登录的项目,用的cas,要把源码的cas-webapp改造成适合我们业务场景的项目,于是新加了一些spring的配置文件. 但是在项目启动时报错了,错误日志如下: 一月 , :: 下午 ...

  2. Spring 循环依赖

    循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...

  3. Springboot源码分析之Spring循环依赖揭秘

    摘要: 若你是一个有经验的程序员,那你在开发中必然碰到过这种现象:事务不生效.或许刚说到这,有的小伙伴就会大惊失色了.Spring不是解决了循环依赖问题吗,它是怎么又会发生循环依赖的呢?,接下来就让我 ...

  4. Spring 循环依赖的三种方式(三级缓存解决Set循环依赖问题)

    本篇文章解决以下问题: [1] . Spring循环依赖指的是什么? [2] . Spring能解决哪种情况的循环依赖?不能解决哪种情况? [3] . Spring能解决的循环依赖原理(三级缓存) 一 ...

  5. Spring循环依赖的解决

    ## Spring循环依赖的解决 ### 什么是循环依赖 循环依赖,是依赖关系形成了一个圆环.比如:A对象有一个属性B,那么这时候我们称之为A依赖B,如果这时候B对象里面有一个属性A.那么这时候A和B ...

  6. 这个 Spring 循环依赖的坑,90% 以上的人都不知道

    1. 前言 这两天工作遇到了一个挺有意思的Spring循环依赖的问题,但是这个和以往遇到的循环依赖问题都不太一样,隐藏的相当隐蔽,网络上也很少看到有其他人遇到类似的问题.这里权且称他非典型Spring ...

  7. Spring — 循环依赖

    读完这篇文章你将会收获到 Spring 循环依赖可以分为哪两种 Spring 如何解决 setter 循环依赖 Spring 为何是三级缓存 , 二级不行 ? Spring 为啥不能解决构造器循环依赖 ...

  8. 帮助你更好的理解Spring循环依赖

    网上关于Spring循环依赖的博客太多了,有很多都分析的很深入,写的很用心,甚至还画了时序图.流程图帮助读者理解,我看了后,感觉自己是懂了,但是闭上眼睛,总觉得还没有完全理解,总觉得还有一两个坎过不去 ...

  9. spring 循环依赖的一次 理解

    前言: 在看spring 循环依赖的问题中,知道原理,网上一堆的资料有讲原理. 但今天在看代码过程中,又产生了疑问. 疑问点如下: // 疑问点: 先进行 dependon 判断String[] de ...

  10. 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖

    本次博客的目标 1. 手写spring循环依赖的整个过程 2. spring怎么解决循环依赖 3. 为什么要二级缓存和三级缓存 4. spring有没有解决构造函数的循环依赖 5. spring有没有 ...

随机推荐

  1. 网站seo优化有什么优缺点

    http://www.wocaoseo.com/thread-94-1-1.html       seo是什么?这个可能是刚刚知道网络营销或搜索引擎营销的朋友们问的话,笔者在这里装一下,呵呵.说真的现 ...

  2. HTTP系列:缓存

    先看一些概念性的术语: 命中率:由缓存提供服务的请求所占的比例被称为缓存命中率: 缓存未命中:其实就是一些到达缓存的请求没有副本可用,而被转发给原始服务器: 再验证:原始服务器上内容可能会发生变化,缓 ...

  3. 使用kind快速创建本地集群

    简 介 kind是另一个Kubernetes SIG项目,但它与minikube有很大区别.它可以将集群迁移到Docker容器中,这与生成虚拟机相比,启动速度大大加快.简而言之,kind是一个使用Do ...

  4. Hihocoder 小Hi小Ho扫雷作死一二三

    这里贴下不用枚举方格是否为雷的方法 a表示输入标号,初始值为-1代表未探知 b表示当前格子是否有雷,初始化为0,0表示未探知,1表示探知肯定有雷,2表示探知肯定无雷(我也不知道为什么不初始化为-1,作 ...

  5. windows环境下利用Gitblit搭建Git服务器并实现自动部署Web站点目录

    Git服务搭建多见于linux环境,但windows主机也不少,目前网上文章诸多不全,且以讹传讹,不甚清楚.下面介绍windows环境下的自动部署和发布. 所需环境及资源:Java环境.Gitblit ...

  6. Eclipse的安装和配置

    1. 下载Eclipse 前往Eclipse官网(https://www.eclipse.org/downloads/packages/)下载Eclipse: 这里下载的版本为: 这里给出该版本的百度 ...

  7. vue、react等SPA应用页脚组件闪烁的解决办法

    大家好,我是木瓜太香.大家在开发单页应用的时候,经常会遇到这样的需求,头部和尾部两个组件是大多数组件公用的,而中间的内容区域则是单独存在的,而且一般内容组件逻辑会比较多,如果我们不停刷新页面可能会出现 ...

  8. Activiti7 网关(包含网关)

    什么是包含网关? 包含网关可以看做是排他网关和并行网关的结合体,和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析他们,但是主要的区别是包含网关可以选择多于一条顺序流,这和并行网关是一样的 ...

  9. .net mvc web api上传图片/文件并重命名

    #region 上传图片 /// <summary> /// 上传图片到服务器 当error为0时成功,为1时失败 并从errmsg获取消息 /// </summary> // ...

  10. linux vi编辑

    编辑模式 使用vi进入文本后,按i开始编辑文本 退出编辑模式 按ESC键,然后: 退出vi :q! 不保存文件,强制退出vi命令 :w 保存文件,不退出vi命令 :wq 保存文件,退出vi命令 中断v ...