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

Spring如何解决循环依赖问题?

getSingleton(String beanName)

在Spring的doGetBean()方法中的第一次调用getSingleton方法(也就是getSingleton(String beanName)方法)中,反映了Spring中针对循环依赖的解决思想。

当Spring容器初始化时,对于每一个声明为单例的Bean,Spring都会创建一个对应的ObjectFactory并将其存储在singletonFactories映射中。在这个映射中,beanName作为键,对应的ObjectFactory作为值。因此,当需要获取一个单例Bean的实例时,Spring会首先尝试从singletonObjects映射中获取该实例。如果该实例不存在,并且允许早期引用(allowEarlyReference为true),那么Spring会从earlySingletonObjects映射中获取该实例。如果仍不存在,Spring会从singletonFactories映射中获取对应的ObjectFactory,并调用其getObject()方法来创建并返回该Bean的实例。

这个ObjectFactory和earlySingletonObjects就是解决循环依赖问题的关键!

// Bean实例的缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);


protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 从缓存中获取
   Object singletonObject = this.singletonObjects.get(beanName);
   // 若缓存内不存在且当前正在创建该单例Bean
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         // 从早期缓存中获取单例实例
         singletonObject = this.earlySingletonObjects.get(beanName);
         // 若早期缓存中不存在且允许早期引用
         if (singletonObject == null && allowEarlyReference) {
            // 获取对应的ObjectFactory
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               // 获取该ObjectFactory对应的实例
               singletonObject = singletonFactory.getObject();
               // 填充早期缓存
               this.earlySingletonObjects.put(beanName, singletonObject);
               // 删除对应的ObjectFactory
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

在这个getSingleton方法中,Spring使用了几个关键的策略和技术来解决循环依赖的问题。

  1. 三级缓存机制:Spring使用了三级缓存机制,即singletonObjectsearlySingletonObjectssingletonFactories。这三个Map结构用于存储不同阶段的单例Bean。
    • singletonObjects:存储完全初始化好的Bean。
    • earlySingletonObjects:存储Bean的早期引用,也就是说Bean已经被实例化了,但是还没进行属性填充和初始化方法。
    • singletonFactories:存储创建Bean的工厂对象,也就是ObjectFactory。
  2. 检查当前Bean是否在创建中isSingletonCurrentlyInCreation(beanName)方法用于检查当前Bean是否正在被创建。如果返回true,说明存在循环依赖。
  3. 同步代码块:当检测到循环依赖时,Spring使用了同步代码块来确保线程安全。这避免了在多线程环境下可能出现的并发问题。
  4. singletonFactories中获取ObjectFactory:如果当前Bean正在创建中并且允许早期引用,Spring会从singletonFactories中获取该Bean的ObjectFactory。
  5. 通过ObjectFactory创建Bean的早期引用:然后调用ObjectFactory的getObject()方法来创建一个该Bean的早期引用,并将其放入earlySingletonObjects缓存中。同时从singletonFactories中移除该ObjectFactory,确保每个Bean只被创建一次。
  6. 解决循环依赖:通过这种机制,即使Bean还没有完全初始化完成,其他依赖于它的Bean也可以通过earlySingletonObjects获取到它的早期引用,从而解决了循环依赖的问题。

总结来说,Spring通过三级缓存机制、同步代码块和ObjectFactory的配合使用,巧妙地解决了循环依赖的问题。这确保了每个Bean只被创建一次,并且在解决依赖关系时线程安全。


http://www.kler.cn/news/155176.html

相关文章:

  • 【EasyExcel实践】导出多个sheet到多个excel文件,并压缩到一个zip文件
  • SmartSoftHelp8,数据库字段详细文档自动生成工具
  • LeetCode 每日一题 2023/11/27-2023/12/3
  • 【数电笔记】18-卡诺图化简
  • 【C++练级之路】【Lv.1】C++,启动!(命名空间,缺省参数,函数重载,引用,内联函数,auto,范围for,nullptr)
  • 锐捷RG-UAC应用网关 前台RCE漏洞复现
  • 说说你对Vue的理解
  • Pytorch中的Net.train()和 Net.eval()函数讲解
  • Java实战案例————ATM
  • 卫星影像数据查询网址(WORLDVIEW1/2/3/4、PLEIADES、SPOT系列、高景、高分1-7、资源系列、吉林一号等)
  • 【Unity动画】为一个动画片段添加事件Events
  • 深度学习——第03章 Python程序设计语言(3.1 Python语言基础)
  • 类和对象(上篇)
  • css中的 Grid 布局
  • 使用docker切换任意版本cuda使用GPU
  • wvp如果确认音频udp端口开放成功
  • 中断方式的数据接收2
  • 在 AlmaLinux9 上安装Oracle Database 23c
  • 回归预测 | MATLAB实现基于LightGBM算法的数据回归预测(多指标,多图)
  • 壹财基金杨振骏:资本如何做好Web3布局?
  • 整数转罗马数字算法(leetcode第12题)
  • 单片机第三季-第六课:STM32标准库
  • sql27(Leetcode1729求关注者的数量)
  • 国家数据局首次国考招聘12人
  • vue面试题整理(1.0)
  • 深入理解 Vue 中的指针操作(二)
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • 跟我学c++高级篇——动态反射之一遍历
  • 代码浅析DLIO(四)---位姿更新
  • LeetCode(49)用最少数量的箭引爆气球【区间】【中等】