IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> spring如何解决循环依赖的 -> 正文阅读

[Java知识库]spring如何解决循环依赖的

1、开篇
本节课会聊聊spring IOC如何解决循环依赖问题。包括如下内容:
● 什么是循环依赖
● Spring IoC处理循环依赖的思路
● 处理循环依赖举例

2、什么是循环依赖
Spring IoC中的循环依赖其实就是循环引用,两个或者两个以上的 Bean 互相持有对方,最终形成闭环。如图1所示,如A依赖于B,B依赖于C,C又依赖于A。这样这样一个场景,初始化A的时候需要完成B的初始化,而完成B的初始化又需要完成C的初始化,最后C又依赖于A,如此这般A永远也无法完成初始化的操作。这种对象的相互依赖形成闭环的关系被称作循环依赖。
在这里插入图片描述

图1 循环依赖
在Spring IoC的使用场景中有两类循环依赖是无解的:
● 构造器的循环依赖:构造器要调用构造函数new 一个对象出来,而参数又依赖于另一个对象。创建类A依赖于类B,new 的时候去创建类B发现类B不存在就会出错拋出 BeanCurrentlyInCreationException 异常。
● prototype 原型bean循环依赖:原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过set方法产生的循环依赖也会抛出异常。
然而针对 singleton bean的循环依赖的场景可以通过三级缓存的方式解决。下面就根据该解决方案展开说明。
3、Spring IoC处理循环依赖的思路

在整理Spring IoC处理singleton bean循环依赖的思路之前先来复习一下bean的生命周期,其包括的三个步骤:
● 实例化:执行了bean的构造方法,bean中依赖的对象还未赋值
● 设置属性:给bean中依赖的对象赋值,若被依赖的对象尚未初始化,则先进行该对象的生命周期(递归)。
● 初始化:执行bean的初始化方法,回调方法等。
解决循环依赖的思路就藏在这三个步骤中,在实例化与设置属性两个步骤之间引入缓存机制,将已经创建好实例但是并没有设置属性的bean放到缓存里,缓存中是没有属性设置的实例对象。假设A对象和B对象互相依赖,A对象的创建需要引用到B对象,而B对象的创建也需要A对象。在创建A对象的时候可以将其放入到缓存中,当B对象创建的时候直接从缓存里引用A对象(此时的A对象只完成了实例化,没有进行设置属性的操作,因此不是完成的A对象,我们称之为半成品A对象),当B对象利用这个半成品的A对象完成实例创建以后(三个步骤都完成),再被A对象引用进去,则A对象也完成了创建。
上文提到的缓存在这里做一个解释,我们将其分为三级,每级缓存都起到不同的作用,如下表格所示:
● 一级缓存:用于存放完全初始化好的 bean,也就是完成三个步骤的bean,拿出来的bean是可以直接使用的。
● 二级缓存:存放原始的 bean 对象,此时的对象只进行了实例化但是没有填充属性,也就是我们所说的“半成品对象”,它的建立是用来解决循环依赖的。
● 三级缓存:用来存放 bean 工厂对象,这个工厂对象是用来产生bean对象的实例的。
在这里插入图片描述

解决循环依赖的整个过程是:
先从一级缓存里取bean实例,如果没有对应的bean实例,二级缓存里取,如果二级缓存中也没有bean实例,singletonFactories三级缓存里获取。由于三级缓存存放着产生bean实例的工厂类,因此可以通过该工厂类产生bean实例。
这里可以调用工厂类暴露的getObject方法返回早期暴露对象引用,也是我们所说的半成品bean,也可以成为earlySingletonObject。并且将这个半成品bean放到二级缓存里,在三级缓存里删除该bean。什么时候这个半成品填充了属性以后,就被移动到一级缓存中,也就是被作为可以使用的已经完成初始化的实例bean了,处理循环依赖的过程宣告完毕。下面通过一个例子让大家更好理解这个思路。
4、处理循环依赖举例
根据上面的思路,这里假设A 和 B 互相依赖,如图2所示,在A 创建实例的时候使用了getBean方法,通过createBeanInstatnce方法对A进行实例化。此时的A只是被实例化出来了,并没有进行填充属性的操作,然后通过addSingletonFactory的方法将创建A的工厂类添加到三级缓存中。上面的思路中提到了这个放到三级缓存中的工厂类是用来生成bean实例用的。
接着往下,当通过populateBean填充实例A属性的时候发现,A依赖B。此时开始通过getBean方法创建B的实例,依旧通过createBeanInstatnce方法对B进行实例化,也把创建B实例的工厂类通过addSingletonFactory方法添加到三级缓存中。在使用populateBean方法填充B的属性时,发现B依赖A,此时通过getBean方法对A进行实例化。
这个时候就出现循环依赖的情况了,getBean方法先从一级缓存中获取 A 的实例,发现没有,再去二级缓存中找,还是找不到,没有办法只有找三级缓存中的A 实例创建工厂去创建A的实例。在前面的步骤中A 已经将工厂类通过addSingletonFactory方法存放到了三级缓存中,于是调用A的工厂类创造A的实例,并且将其放到二级缓存中返回给B 用来填充B的属性,当B完成属性填充以后产生了B的实例,返回给populateBean(A)使用,此时A获取了B的实例(完成属性填充的B实例)。
所以,A 也可以完成属性填充从而产生A 的初始化以后的实例并且将其放到一级缓存中。由于B之前使用的是A的实例是没有做属性填充的,也就是半成品的A实例,因此此时从一级缓存中获取成品的A实例完成B对象的初始化。
在这里插入图片描述

图2 A B 相互循环依赖,如何处理。
5、总结
本节课提出了Spring IoC遇到的循环依赖的问题,并且通过分析bean创建的过程和三级缓存技术,找到了解决singleton bean 循环依赖的办法,然后通过一个简单的循环依赖处理的例子加强对这一思路的理解。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-20 15:39:09  更:2021-09-20 15:41:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:12:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码