当前位置: 首页 > news >正文

Spring 循环依赖详解

目录

1.为什么会产生循环依赖

了解Bean生命周期

循环依赖的产生:

2.Spring 中对循环依赖的解决


1.为什么会产生循环依赖

Spring IOC容器是用来管理java Bean 对象的,而Spring DI 是依赖注入,即就是给某个java Bean对象将所依赖的java Bean对象注入到Bean对象的属性。

了解Bean生命周期

其次就是IOC容器中Bean 对是有生命周期的(Bean对象创建初始化销毁步骤):

1,实例化(创建半成品Bean对象):读取配置文件,将每个Bean对象信息封装到BeanDifinition对象中,将其放到BeanDifinitionMap中,然后执行一些Bean工厂后处理器中的方法,最后读取BeanDifinition中的Bean信息,创建出一个Bean对象

2,初始化(对半成品Bean对象进行依赖注入,产生最后的Bean对象):属性赋值,Bean后处理器Before(),接口初始化,自定义初始化,Bean后处理器的after(),Bean对象创建完成放到singletonObjects Map中。

3,getBean()调用singletonObjects Map中的对

4,接口销毁,自定义销毁,


循环依赖的产生:

之所以会有循环依赖是因为Bean对象的生命周期中的步骤产生的问题:

分析上图AC两个对象的生命周期:

由于一个Bean对象只有执行到初始化完,才会被放到容器singletonObjects Map中,而上面说的AC两个对象互相依赖,即每个对象(A)在进行到初始化的赋值中的时候,都要去容器singletonObjects Map 中寻找它自己所依赖的对象(C),找不见则去创建自己所依赖的对象(C),这时A还没被放入singletonObjects Map中,再去创建自己所依赖的对象(C),然而到初始化赋值的时候在容器又没找到自己所依赖对象(A),再去创建对象A,这样A,C永远都不可能创建完成,产生了循环依赖.

2.Spring 中对循环依赖的解决

Spring提供了三级缓存存储,为 完整Bean实例 (一级缓存<singletonObjects Map>)和 未被引用的半成品Bean实例(三级缓存<singletonFactories>) ,被引用的半成品Bean实例(二级缓存<earlySingletonObjects>),提供存放的位置,用于解决循环引用问题

在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:

 public class DefaultSingletonBeanRegistry ... {//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三
级缓存"Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,未来通过此接口对应的get方法再
次提取对象

Bean A和Bean C循环依赖的过程结合上述三级缓存描述如下:

A实例化对象,但尚未初始化,将A存储到三级缓存;

A属性注入,需要B,从缓存中获取,没有B;

B实例化对象,但尚未初始化,将B存储到到三级缓存;

B属性注入,需要A,从三级缓存获取A,A从三级缓存移 入二级缓存;

B执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;

A注入B; A执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓 存。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于python opencv 多进程处理图像
  • 你了解你的GD32 MCU系统主频是多少吗 ?
  • 什么是反射以及反射的应用及例子
  • 14、如何⽤DDD设计微服务代码模型
  • [Armbian] 部署Docker版Home Assistent,安装HACS并连接米家设备
  • SimD~
  • 数据结构之树知识总结
  • 快速搞定分布式RabbitMQ---RabbitMQ进阶与实战
  • 【C++笔试强训】day02
  • Android SurfaceFlinger——纹理的绘制流程(二十八)
  • Activiti 6 兼容openGauss数据库bytes类型不匹配
  • Linux 某进程 CPU 高问题,用 Shell 脚本发现处理
  • go标准库---net/http服务端
  • 被工信部认可的开源软件治理解决方案
  • 高级及架构师高频面试题-应用型
  • 【笔记】你不知道的JS读书笔记——Promise
  • Android 控件背景颜色处理
  • Android单元测试 - 几个重要问题
  • DOM的那些事
  • HomeBrew常规使用教程
  • java8-模拟hadoop
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • LeetCode18.四数之和 JavaScript
  • Linux下的乱码问题
  • MobX
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • vue 个人积累(使用工具,组件)
  • vue-cli3搭建项目
  • 阿里云Kubernetes容器服务上体验Knative
  • 猴子数据域名防封接口降低小说被封的风险
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 小程序button引导用户授权
  • 学习笔记TF060:图像语音结合,看图说话
  • 原生js练习题---第五课
  • 再谈express与koa的对比
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • # 利刃出鞘_Tomcat 核心原理解析(七)
  • #QT(智能家居界面-界面切换)
  • $.each()与$(selector).each()
  • (02)Hive SQL编译成MapReduce任务的过程
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (js)循环条件满足时终止循环
  • (Windows环境)FFMPEG编译,包含编译x264以及x265
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (六)c52学习之旅-独立按键
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (十三)Flink SQL
  • (四)模仿学习-完成后台管理页面查询
  • (一一四)第九章编程练习
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)Scala的“=”符号简介
  • (转)人的集合论——移山之道
  • .ai域名是什么后缀?