在Spring中如何处理循环依赖问题

 更新时间:2025年01月07日 08:38:05   作者:MuseLss  
Spring解决循环依赖的关键在于提前曝光未完全创建的bean,在Spring中创建Bean分为实例化、属性填充和初始化三步,循环依赖的解决思路是先创建A的bean实例,此时A是不完整的,用一个Map保存不完整的A,再创建B,B需要注入A

Spring如何处理循环依赖

解决的关键就在于提前曝光未完全创建的bean。

在Spring中创建Bean分为三步

  • 实例化,createBeanInstance,即new一个bean对象。
  • 属性填充,populateBean,即往bean对象中set属性值。
  • 初始化,initializeBean。

循环依赖的解决思路

  • 先创建A的bean实例,此时的A是不完整的,因为没有属性填充(即B依赖没有注入),此时用一个Map保存不完整的A,
  • 再创建B,B需要注入A,所以可以从Map中得到不完整的A,此时B就完整了,然后A就可以注入B了。

在Spring中,只有同时满足以下两点才能解决循环依赖的问题。

1.依赖的bean必须都是单例。

  • 因为如果是原型模式的话是需要创建一个新的对象,创建A1的时候,需要创建A1的依赖B1
  • 那么在创建B1的时候,又需要创建B1的依赖A2,这样就要创建B2,A3,B3……,进入无限的创建对象的过程

2.依赖注入的方式,不能全是构造函数注入。

  • 如果全是构造函数注入,即A(B b) ,那么表明在创建A的Bean的实例的时候,就需要得到B,那么此时就要创建B的bean实例,但是B也是要在构造函数中注入A,即B(A a),此时B需要在Map中找到不完整的A,但是发现找不到,因为A的Bean实体还没创建完(还在等着B)。
  • 注意:Spring容器是按照字母的顺序创建 Bean的,因此循环依赖中,字母排在前面的Bean不能采用构造函数注入。

Sping解决循环依赖全流程

首先了解Spring bean相关的三个Map

  • singletonObject,存放所有创建完毕的单例bean(完整的bean,即已经完成实例化并进行属性填充)。
  • earlySingletonObjects,存放仅完成实例化,但未进行属性填充和初始化的Bean。
  • singletonfactories,存放能创建Bean的工厂,通过这个工厂能获得bean,延迟bean生成,工厂生成的bean会放到earlySingletonObjects中。

在实例化bean,Spring是不知道当前bean有没有循环依赖的,它会义无反顾的往singletonfactories中存放当前bean的工厂,这个步骤就是提前曝光

然后开始属性注入,此时bean A发现要注入bean B,所以请执行getBean(B)

  • 先去singletonObject里找有没有,如果有则进行返回
  • 如果没有,则判断Bean是否在创建中,如果不在创建中,则返回null
  • 如果在创建中,则去earlySingletonObjects找,如果有则进行返回
  • 如果没有,则去singletonfactories找到这个bean的工厂,通过工厂去创建bean,并存放到earlySingletonObjects中
  • 如果singletonfactories没有找到bean的工厂就返回null
  • 如果返回null,说明bean还没有创建,这个时候会先把这个bean标记为创建中,再调用doCreateBean(即,实例化,属性填充,初始化三个步骤)

此时就到了B这个bean属性注入的步骤了,调用了getBean(A),A此时在singletonfactories中找到提前暴露的工厂的到了A,然后把A从singletonfactories中删除,放到earlySingletonObjects中。

此时B属性注入成功,然后进行初始化,最后B存放到singletonObject中。

此时又回到了A注入B的地方,完成了对B的注入,然后A也从earlySingletonObjects删除,存放到singletonObject中。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • maven项目打包上传到私有仓库

    maven项目打包上传到私有仓库

    在项目开发中通常会引用其他的jar,怎样把自己的项目做为一个jar包的形式发布到私服仓库中,本文就详细的介绍一下,感兴趣的可以了解一下
    2021-06-06
  • SpringCloud中分析讲解Feign组件添加请求头有哪些坑梳理

    SpringCloud中分析讲解Feign组件添加请求头有哪些坑梳理

    在spring cloud的项目中用到了feign组件,简单配置过后即可完成请求的调用。又因为有向请求添加Header头的需求,查阅了官方示例后,就觉得很简单,然后一顿操作之后调试报错...下面我们来详细了解
    2022-06-06
  • Java 照片对比功能的实现

    Java 照片对比功能的实现

    这篇文章主要介绍了Java 照片比对功能实现类的示例代码,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-12-12
  • java实现题目以及选项乱序的方法实例

    java实现题目以及选项乱序的方法实例

    这篇文章主要给大家介绍了关于java实现题目以及选项乱序的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 华为鸿蒙系统应用开发工具 DevEco Studio的安装和使用图文教程

    华为鸿蒙系统应用开发工具 DevEco Studio的安装和使用图文教程

    HUAWEI DevEco Studio 是华为消费者业务为开发者提供的集成开发环境(IDE),旨在帮助开发者快捷、方便、高效地使用华为EMUI开放能力。这篇文章主要介绍了华为鸿蒙系统应用开发工具 DevEco Studio的安装和使用图文教程,需要的朋友可以参考下
    2021-04-04
  • 实例展示使用Java压缩和解压缩7z文件的方法

    实例展示使用Java压缩和解压缩7z文件的方法

    这篇文章主要介绍了实例展示使用Java压缩和解压缩7z文件的方法,用到了7-zip的开源项目7-zip-JBinding,需要的朋友可以参考下
    2015-11-11
  • Java使用Statement接口执行SQL语句操作实例分析

    Java使用Statement接口执行SQL语句操作实例分析

    这篇文章主要介绍了Java使用Statement接口执行SQL语句操作,结合实例形式详细分析了Java使用Statement接口针对mysql数据库进行连接与执行SQL语句增删改查等相关操作技巧与注意事项,需要的朋友可以参考下
    2018-07-07
  • Java中的2种集合排序方法介绍

    Java中的2种集合排序方法介绍

    这篇文章主要介绍了Java中的2种集合排序方法介绍,本文直接给出代码,相关说明请看代码中的注释,需要的朋友可以参考下
    2014-10-10
  • Spring配置文件解析之BeanDefinitionParserDelegate详解

    Spring配置文件解析之BeanDefinitionParserDelegate详解

    这篇文章主要介绍了Spring配置文件解析之BeanDefinitionParserDelegate详解,对于Spring的配置文件的解析处理操作是在BeanDefinitionParserDelegate中进行处理操作,接下来我们简单介绍一下BeanDefinitionParserDelegate所做的处理操作,需要的朋友可以参考下
    2024-02-02
  • Java让泛型实例化的方法

    Java让泛型实例化的方法

    这篇文章主要介绍了Java让泛型实例化的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07

最新评论