SpringIOC循环依赖
1. 什么是循环依赖
循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A

注意:
这⾥不是函数的循环调⽤,是对象的相互依赖关系。
循环调⽤其实就是⼀个死循环,除⾮有终结 条件。
Spring中循环依赖场景有:
- 构造器的循环依赖(构造器注⼊)
- Field 属性的循环依赖(set注⼊)
其中,构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,spring采⽤的是提前暴露对象的⽅法。
2. 循环依赖处理机制
- 单例 bean 构造器参数循环依赖(⽆法解决)
- prototype 原型 bean循环依赖(⽆法解决)
因为prototype 原型 bean ,产生对象之后是不在容器中管理的。 - 单例bean通过setXxx或者@Autowired进行循环依赖(可以解决)
2.1 演示场景:
//lagouBen 依赖于 ItBean
public class LagouBean {
private ItBean itBean;
public void setItBean(ItBean itBean) {
this.itBean = itBean;
}
public LagouBean() {
System.out.println("LagouBean 构造器");
}
}
//ItBean 依赖于 LagouBen
public class ItBean {
private LagouBean lagouBean;
public void setLagouBean(LagouBean lagouBean) {
this.lagouBean = lagouBean;
}
public ItBean() {
System.out.println("ItBean...构造器");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="lagouBean" class="com.lagou.edu.LagouBean" >
<property name="ItBean" ref="itBean>"></property>
</bean>
<bean id="itBean" class="com.lagou.edu.ItBean" >
<property name="LagouBean" ref="lagouBean>"></property>
</bean>
</beans>
2.2 处理机制简图


总结:
A依赖于B ,B 依赖于A
A在创建过程中 :
首先会创建Bean实例(仅仅调用构造方法,但是尚未设置属性,通过反射完成对象的初始化),
然后判断是否是单例,是否有循环依赖。
把创建好的Bean实例放入三级缓存——singletonFactories

然后将要给A Bean装配属性,发现依赖B

调用deGetBean() 想拿到B,首先从一级缓存(singletonObjects)中拿,然后从二级缓存中(earlySingletonObjects)拿,然后从三级缓存(singletonFactories)拿,都拿不到,那就开始创建B Bean

把创建好的B Bean实例放入三级缓存——singletonFactories,发现依赖于A
调用deGetBean() 想拿到A,首先从一级缓存(singletonObjects)中拿,然后从二级缓存中(earlySingletonObjects)拿,都没拿到。然后从三级缓存中拿,拿到了

拿到A Bean之后如上图,放到二级缓存(earlySingletonObjects)中,然后从三级缓存(singletonFactories)中删除。然后给B bean赋值了。
此时B Bean 就装配好了 放入一级缓存池中。
B 装配好了之后,A 就能顺利的装配了,然后调用
addSingleton()方法,把A 从二级三级缓存中删除,然后放到一级缓存也就是单例池中。

完成
注意:
这个案例中,B不会放到二级缓存,只有在B依赖的一个对象尚未实例化的时候才会把B放到二级缓存。例如:
A依赖B,B依赖A和C,C依赖B。 先创建A,把尚未赋值的A放到三级缓存,然后赋值B,找不到B,然后创建B,然后把尚未赋值的B放到三级缓存,然后在创建B的过程中从三级缓存找A(同时把A从三级缓存中删除然后加入到二级缓存),然后B还有个属性C,赋值C,从缓存中找不到C,然后创建C,然后把尚未赋值的B放到三级缓存,创建C的过程中发现C依赖于B,然后可以从三级缓存中找到B,然后把B放到二级缓存,C就装配完毕了,放到一级缓存。同时B也有了A和C,B装配完毕了,放到一级缓存。 A依赖B,B已经OK了,那么A也装配完毕了。
/** Cache of singleton factories: bean name to ObjectFactory. */
//三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
//二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** Cache of singleton objects: bean name to bean instance. */
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
SpringIOC循环依赖的更多相关文章
- kmdjs和循环依赖
循环依赖 循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚.所以没解决好循环依赖的模块化库.框架.编译器都不是一个好 ...
- spring3 循环依赖
循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...
- 在.NET Core中遭遇循环依赖问题"A circular dependency was detected"
今天在将一个项目迁移至ASP.NET Core的过程中遭遇一个循环依赖问题,错误信息如下: A circular dependency was detected for the service of ...
- seaJS循环依赖的解决原理
seajs模块的六个状态. var STATUS = { 'FETCHING': 1, // The module file is fetching now. 模块正在下载中 'FETCHED': ...
- RequireJS 循环依赖报 模块undefined 处理方案
RequireJS 循环依赖 开始学习使用RequireJS之后做了几个小例子,之后想着把手头的项目也用RequireJS写一遍试试.感觉胜利就在前方了,忽然发现始终卡在一个问题上: 很常见的一个问题 ...
- 剑指架构师系列-Struts2构造函数的循环依赖注入
Struts2可以完成构造函数的循环依赖注入,来看看Struts2的大师们是怎么做到的吧! 首先定义IBlood与BloodImpl类: public interface IBlood { } pub ...
- Spring的循环依赖问题
spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢?首先让我们来定义循环引用类: 在Spring中将循环依赖的处理分成了3种情况: 构造器循环依赖 ...
- Spring对加载的bean之间循环依赖的处理
根据下面文档的叙述,简言之: 对于相互之间通过构造函数注入相互循环依赖的情况,Spring会抛出BeanCurrentlyInCreationException错误. 如果AB两个beans是通过属性 ...
- DI 之 3.2 循环依赖 (伍)
3.2.1 什么是循环依赖 循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA, ...
随机推荐
- NB-IoT应用分类与技术特点分析
NB-Iot作为一种窄带物联网技术在各大行业脱颖而出,其应用涵盖多个领域.此文计讯小编将讲解NB-IoT的主要应用分类及相关特点. 一.NB-IoT是什么 NB-IoT是指窄带物联网(Na ...
- java的高并发IO原理,阻塞BIO同步非阻塞NIO,异步非阻塞AIO
原文地址: IO读写的基础原理 大家知道,用户程序进行IO的读写,依赖于底层的IO读写,基本上会用到底层的read&write两大系统调用.在不同的操作系统中,IO读写的系统调用的名称可能不完 ...
- mac下docker安装php链接使用国产数据库驱动
docker下配置php macos系统无法使用神通数据库,所以使用docker来安装php 第一步先安装php docker search php docker pull php:7.1-fpm d ...
- c#习题之2
string str = null; Console.WriteLine("请输入一个字符串"); str = Console.ReadLine(); char[] c = new ...
- 5、Python语法之基本数据类型
一 引入 我们学习变量是为了让计算机能够像人一样去记忆事物的某种状态,而变量的值就是用来存储事物状态的,很明显事物的状态分成不同种类的(比如人的年龄,身高,职位,工资等等),所以变量值也应该有不同的类 ...
- 1、Web应用
一 Web应用的组成 接下来我们学习的目的是为了开发一个Web应用程序,而Web应用程序是基于B/S架构的,其中B指的是浏览器,负责向S端发送请求信息,而S端会根据接收到的请求信息返回相应的数据给浏览 ...
- vgg学习
LeNet-5是一个较简单的卷积神经网络.下图显示了其结构:输入的二维图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层. AlexNet中包含了几个比较新的技术点, ...
- spring-cloud-config 多服务共享公共配置的解决方案总结,太全了!
问题描述 我们公司的项目是基于SpringCloud开发的微服务,用到了Spring-Cloud-Config作为微服务统一的配置中心,可以将散落在各个服务的配置进行统一配置管理. 虽然配置中心将各个 ...
- 流量控制--3.Linux流量控制的组件
Linux流量控制的组件 流量控制元素与Linux组件之间的相关性: traditional element Linux component 入队列 修订:从用户或网络接收报文 整流 class 提供 ...
- 极客mysql08
1.innodb支持RC和RR隔离级别实现是用的一致性视图(consistent read view) 2.事务在启动时会拍一个快照,这个快照是基于整个库的. 基于整个库的意思就是说一个事务内,整个库 ...