Spring循环依赖的解决方法详解

目录
  • 什么是循环依赖:
  • Spring实例Bean的本质
  • 循环依赖主要场景
  • 什么情况下循环依赖可以被解决
  • 解决方式

说明:spring如何解决循环依赖,是面试中经常问到的题目,今天我们就来分享一下spring是如何解决循环依赖问题的。

什么是循环依赖:

我们先来看看官方文档的说法:

通俗来讲,就是A依赖B或者B依赖A,或者C依赖自己本身,或是三个以上,例如A依赖B,B依赖C,C又依赖A。如下图:

Spring实例Bean的本质

Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。

循环依赖主要场景

什么情况下循环依赖可以被解决

Spring解决循环依赖是有前置条件的

  • 出现循环依赖的Bean必须要是单例(singleton),如果依赖prototype则完全不会有此需求。
  • 依赖注入的方式不能全是构造器注入的方式。

解决方式

Spring是通过三级缓存来解决上述问题的:

一级缓存: singletonObjects存储的是所有创建好了的单例Bean

二级缓存:earlySingletonObjects完成实例化,但是还未进行属性注入及初始化的对象

三级缓存:singletonFactories提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象。

三级缓存解决循环依赖流程:

  1. 获取A时首先会尝试从一级缓存singletonObjects中获取;
  2. 获取不到就再从二级缓存earlySingletonObjects中获取;
  3. 若是还没有则尝试从三级缓存singletonFactories获取;
  4. 还是没有获取到则再尝试创建A对象
  5. 会执行doGetBean->createBean->createBeanInstance并使用构造器实例化
  6. 在尝试给A进行初始化时,由于B不存在无法完成初始化,则将半成品A放入第二级缓存中,进入B的创建流程。
  7. 与先前过程相似,在第三级缓存中放入beanName和表达式sharedInstance,进入B的初始化过程
  8. 由于在第二级缓存中可以找到A,则B可以完成初始化,将成品Bean放入一级缓存中备用,删除三级缓存中的B
  9. 同时完成A的初始化,并删除二级缓存中的半成品A

具体流程图如下:

最后我们来个小小的总结:

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。

当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。

当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取。

  • 先获取到三级缓存中的工厂;
  • 调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。
  • 当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!

到此这篇关于Spring循环依赖的解决方法详解的文章就介绍到这了,更多相关Spring循环依赖内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring循环依赖的解决方案详解

    目录 简介 方案1. Feild注入单例(@AutoWired) 方案2. 构造器注入+@Lazy 方案3. Setter/Field注入单例 方案4. @PostConstruct 方案5. 实现ApplicationContextAware与InitializingBean 简介 说明 本文用实例介绍如何解决Spring的循环依赖问题. 相关网址 Spring循环依赖之问题复现详解 公共代码 package com.example.controller; import com.example

  • spring如何快速稳定解决循环依赖问题

    循环依赖其实就是循环引用,很多地方都说需要两个或则两个以上的bean互相持有对方最终形成闭环才是循环依赖,比如A依赖于B,B依赖于C,C又依赖于A.其实一个bean持有自己类型的属性也会产生循环依赖. setter singleton循环依赖 使用 SingleSetterBeanA依赖SingleSetterBeanB,SingleSetterBeanB依赖SingleSetterBeanA. @Data public class SingleSetterBeanA { @Autowired

  • Spring解决循环依赖的方法(三级缓存)

    说起Spring,作为流水线上装配工的小码农,可能是我们最熟悉不过的一种技术框架.但是对于Spring到底是个什么东西,我猜作为大多数的你可能跟我一样,只知道IOC.DI,却并不明白这其中的原理究竟是怎样的.在这儿你可能想得完整的关于Spring相关的知识,但是我要告诉你对不起.这里不是教程,只能作为你窥探spring核心的窗口.我不做教程,因为网上的教程.源码解析太多,你可以自行选择学习.但我要提醒你的是,看再多的教程也不如你一次的主动去追踪源码. 好了,废话说了这么多就是提醒你这里不是一个教

  • spring如何解决循环依赖问题详解

    循环依赖其实就是循环引用,很多地方都说需要两个或则两个以上的bean互相持有对方最终形成闭环才是循环依赖,比如A依赖于B,B依赖于C,C又依赖于A.其实一个bean持有自己类型的属性也会产生循环依赖. setter singleton循环依赖 使用 SingleSetterBeanA依赖SingleSetterBeanB,SingleSetterBeanB依赖SingleSetterBeanA. @Data public class SingleSetterBeanA { @Autowired

  • 关于spring循环依赖问题及解决方案

    目录 一.三种循环依赖的情况 比如几个Bean之间的互相引用 甚至自己“循环”依赖自己 二.解决方案 如何获取依赖 三.解决循环依赖必须要三级缓存吗 结论 四.无法解决的循环依赖问题 1.在主bean中通过构造函数注入所依赖的bean 2.总结 一.三种循环依赖的情况 ①构造器的循环依赖: 这种依赖spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常. ②单例模式下的setter循环依赖: 通过“三级缓存”处理循环依赖,能处理. ③非单例循环依赖

  • Spring使用三级缓存解决循环依赖的问题

    Spring如何使用三级缓存解决循环依赖在没开始文章之前首先来了解一下什么是循环依赖 @Component public class A { @Autowired B b; } @Component public class B { @Autowired A a; } 在对象A创建过程中,需要注入B,因为容器中没有B,则去创建B,B创建过程中又需要注入A,而A在等待B的创建,B在等待A的创建,导致两者都无法创建成功,无法加入到单例池供用户使用. Spring则通过三级缓存来解决循环依赖的问题,另

  • 你知道怎么用Spring的三级缓存解决循环依赖吗

    目录 1. 前言 2. Spring Bean的循环依赖 3. Spring中三大循环依赖场景演示 3.1 构造器注入循环依赖 3.2 singleton模式field属性注入循环依赖 3.3 prototype模式field属性注入循环依赖 4. Spring解决循环依赖的原理分析 4.1 Spring创建Bean的流程 4.2 Spring容器的“三级缓存” 4.3 源码解析 4.4 流程总结 5. 总结 1. 前言 循环依赖:就是N个类循环(嵌套)引用. 通俗的讲就是N个Bean互相引用对

  • Spring三级缓存解决循环依赖

    目录 一级缓存 为什么不能在实例化A之后就放入Map? 二级缓存 二级缓存已然解决了循环依赖问题,为什么还需要三级缓存? 三级缓存 源码 我们都知道Spring中的BeanFactory是一个IOC容器,负责创建Bean和缓存一些单例的Bean对象,以供项目运行过程中使用. 创建Bean的大概的过程: 实例化Bean对象,为Bean对象在内存中分配空间,各属性赋值为默认值 初始化Bean对象,为Bean对象填充属性 将Bean放入缓存 首先,容器为了缓存这些单例的Bean需要一个数据结构来存储,

  • Spring为何需要三级缓存解决循环依赖详解

    目录 前言 bean生命周期 三级缓存解决循环依赖 总结 前言 在使用spring框架的日常开发中,bean之间的循环依赖太频繁了,spring已经帮我们去解决循环依赖问题,对我们开发者来说是无感知的,下面具体分析一下spring是如何解决bean之间循环依赖,为什么要使用到三级缓存,而不是二级缓存 bean生命周期 首先大家需要了解一下bean在spring中的生命周期,bean在spring的加载流程,才能够更加清晰知道spring是如何解决循环依赖的 我们在spring的BeanFacto

  • Spring循环依赖的解决方法详解

    目录 什么是循环依赖: Spring实例Bean的本质 循环依赖主要场景 什么情况下循环依赖可以被解决 解决方式 说明:spring如何解决循环依赖,是面试中经常问到的题目,今天我们就来分享一下spring是如何解决循环依赖问题的. 什么是循环依赖: 我们先来看看官方文档的说法: 通俗来讲,就是A依赖B或者B依赖A,或者C依赖自己本身,或是三个以上,例如A依赖B,B依赖C,C又依赖A.如下图: Spring实例Bean的本质 Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所

  • Spring中循环依赖的解决方法详析

    前言 说起Spring中循环依赖的解决办法,相信很多园友们都或多或少的知道一些,但当真的要详细说明的时候,可能又没法一下将它讲清楚.本文就试着尽自己所能,对此做出一个较详细的解读.另,需注意一点,下文中会出现类的实例化跟类的初始化两个短语,为怕园友迷惑,事先声明一下,本文的实例化是指刚执行完构造器将一个对象new出来,但还未填充属性值的状态,而初始化是指完成了属性的依赖注入. 一.先说说Spring解决的循环依赖是什么 Java中的循环依赖分两种,一种是构造器的循环依赖,另一种是属性的循环依赖.

  • SpringBoot循环依赖之问题复现详解

    目录 简介 问题复现 1.构造器注入 2.Feild注入多例(@AutoWired) 3.Setter注入多例(@AutoWired) 解决方案 简介 说明 本文介绍Spring的循环依赖什么时候会出现以及如何解决循环依赖. 循环依赖场景 1.单例field的循环依赖       (采用三级缓存+提前暴露对象的方法解决) 2.构造器的循环依赖          (无法解决循环依赖问题) 3.多例field的循环依赖       (无法解决循环依赖问题) 对于多例的bean,Spring不缓存"p

  • Spring事务管理原理及方法详解

    这篇文章主要介绍了Spring事务管理原理及方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 事务,在日常开发或者面试中都必定会涉及到.开发工作中,结合数据库开发理解就是:一组dml要么全部成功执行提交,要么因为某一个操作异常,撤销之前所做的成功的操作,整体执行失败.再简单点的一句话:生死与共. 由此,可以看出,事务的必要性:在开发工作中,保证操作数据的安全性.事务的控制也就是保证数据的访问安全性. 一.事务的四大特性 A:原子性(ato

  • Spring循环依赖的解决办法,你真的懂了吗

    介绍 先说一下什么是循环依赖,循坏依赖即循环引用,两个或多个bean相互引用,最终形成一个环.Spring在初始化A的时候需要注入B,而初始化B的时候需要注入A,在Spring启动后这2个Bean都要被初始化完成 Spring的循环依赖有两种场景 构造器的循环依赖 属性的循环依赖 构造器的循环依赖,可以在构造函数中使用@Lazy注解延迟加载.在注入依赖时,先注入代理对象,当首次使用时再创建对象完成注入 属性的循环依赖主要是通过3个map来解决的 构造器的循环依赖 @Component publi

  • PHP内存溢出的解决方法详解

    目录 1.处理数组时出现内存溢出 2.使用sql查询数据,查出来很多,导致内存溢出 3.假定日志中存放的记录数为500000条,那么解决方案如下 4.上传excel文件时,出现内存溢出的情况 什么是内存溢出 内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存. 引起内存溢出的原因有很多种,常见的有以下几种: 1 内存中加载的数据量过于庞大,如一次从数据库取出过多数据: 2 集合类中有对对象的引用,使用完后未清空: 3 代码中存在死循环

  • 线上Spring CPU 高负载解决思路详解

    目录 引言 定位问题 日志搜索 监控看板 ThreadDump 优化 事后反思 引言 背景: 在某一天,运营同事突然发现运营看板好几天没有更新数据了, 然后找了过来?! 这里看似抛出了一个问题 ? 但细想一下, 同时暴露了我们对于线上服务的监控未完全覆盖到!!! 这是致命的!!! 当然, 这篇文章先不讨论监控的问题, 后面会推出完善的监控方案 定位问题 问题抛过来了, 那么我们第一步要怎样做呢? 拿到问题的第一步, 先理解题意, 这里有几个关键的信息点 第一 : 好几天, 具体哪一天, 这个后面

  • FileZilla Server搭建FTP服务器配置及425错误与TLS警告解决方法详解

    我们为大家提供FileZilla下载链接: FileZilla 客户端:FileZilla_3.24.0_win64-setup.exe: FileZilla Server服务端绿色汉化版:FileZilla_Server-0_9_59.exe: 在服务器上安装并配置服务端: 安装过程这里不再赘述,一直下一步,在跳出弹窗时勾选"Always connect to this server",然后点击"Connect"即可(密码可自行设置或者为空): 默认安装完会有如下

  • Python安装依赖(包)模块方法详解

    Python模块,简单说就是一个.py文件,其中可以包含我们需要的任意Python代码.迄今为止,我们所编写的所有程序都包含在单独的.py文件中,因此,它们既是程序,同时也是模块.关键的区别在于,程序的设计目标是运行,而模块的设计目标是由其他程序导入并使用. 不是所有程序都有相关联的.py文件-比如说,sys模块就内置于Python中,还有些模块是使用其他语言(最常见的是C语言)实现的.不过,Python的大多数库文件都是使用Python实现的,因此,比如说,我们使用了语句import coll

  • python爬虫泛滥的解决方法详解

    我们可以把互联网上搬运数据的程序看成小蚂蚁,它们需要采集不同的食物带回洞里存储.但是大家也知道白蚁泛滥的事件,在我们的网络环境里,如果爬虫都集中在某几个位置,最直接的结果就是这个网站的拥挤.对于我们这些网站访问者而言也不是好事情,首先网页的页面会被卡住.网站的管理人员面对爬虫过多,这时候就要进行一系列的限制措施了,这里小编分了两个大的应对方向,从不同的角度进 行分析爬虫过多的解决思路. 一.识别爬虫 1. HTTP请求头 这算是最基础的网络爬虫识别了,正常的网络访问者都是通过浏览器对网站进行访问

随机推荐