一、什么是循环依赖

  多个bean之间相互依赖,形成了一个闭环。 比如:A依赖于B、B依赖于c、c依赖于A

  通常来说,如果问spring容器内部如何解决循环依赖, 一定是指默认的单例Bean中,属性互相引用的场景。也就是说,Spring的循环依赖,是Spring容器注入时候出现的问题。

    

二、Spring如何解决循环依赖

1,Spring中单例Bean的三级缓存

  

  • 第一级缓存〈也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象
  • 第二级缓存: earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)
  • 第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂

2,Spring中Bean的生命周期

      

     

3,Bean初始化主要方法

  

  • getSingleton:希望从容器里面获得单例的bean,没有的话
  • doCreateBean: 没有就创建bean
  • populateBean: 创建完了以后,要填充属性
  • addSingleton: 填充完了以后,再添加到容器进行使用

4,具体说明

  • A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B
  • B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
  • B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A放到一级缓存中。

5,图解

  

三、为什么使用三级缓存

1,使用一级缓存

  实例化A -> 将半成品的A放入singletonObjects中->填充A的属性时发现取不到B->实例化B->从singletonObjects中取出A填充B的属性->将成品B放入singletonObjects->将B填充到A的属性中->将成品A放入singletonObjects。

  问题:这种基本流程是通的,但是如果在整个流程进行中,有另一个线程要来取A,那么有可能拿到的只是一个属性都为null的半成品A,这样就会有问题。

2,使用二级缓存

a)使用singletonObjects和earlySingletonObjects

  成品放在singletonObjects中,半成品放在earlySingletonObjects中

  流程可以这样走:实例化A ->将半成品的A放入earlySingletonObjects中 ->填充A的属性时发现取不到B->实例化B->将半成品的A放入earlySingletonObjects中->从earlySingletonObjects中取出A填充B的属性->将成品B放入singletonObjects,并从earlySingletonObjects中删除B->将B填充到A的属性中->将成品A放入singletonObjects并删除earlySingletonObjects。

  问题:这样的流程是线程安全的,不过如果A上加个切面(AOP),这种做法就没法满足需求了,因为earlySingletonObjects中存放的都是原始对象,而我们需要注入的其实是A的代理对象

b)使用singletonObjects和singletonFactories

  成品放在singletonObjects中,半成品通过singletonFactories来获取

  流程是这样的:实例化A ->创建A的对象工厂并放入singletonFactories中 ->填充A的属性时发现取不到B->实例化B->创建B的对象工厂并放入singletonFactories中->从singletonFactories中获取A的对象工厂并获取A填充到B中->将成品B放入singletonObjects,并从singletonFactories中删除B的对象工厂->将B填充到A的属性中->将成品A放入singletonObjects并删除A的对象工厂。

  问题:这样的流程也适用于普通的IOC以及有并发的场景,但如果A上加个切面(AOP)的话,这种情况也无法满足需求

Spring如何解决循环依赖的更多相关文章

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

    在关于Spring的面试中,我们经常会被问到一个问题,就是Spring是如何解决循环依赖的问题的. 这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能 ...

  2. Spring如何解决循环依赖问题

    目录 1. 什么是循环依赖? 2. 怎么检测是否存在循环依赖 3. Spring怎么解决循环依赖 本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可 ...

  3. Spring 如何解决循环依赖的问题

    Spring 如何解决循环依赖的问题 https://blog.csdn.net/qq_36381855/article/details/79752689 Spring IOC 容器源码分析 - 循环 ...

  4. 一张图彻底理解Spring如何解决循环依赖!!

    写在前面 最近,在看Spring源码,看到Spring解决循环依赖问题的源码时,不得不说,源码写的太烂了.像Spring这种顶级的项目源码,竟然存在着这种xxx的代码.看了几次都有点头大,相信很多小伙 ...

  5. Spring中解决循环依赖报错的问题

    什么是循环依赖 当一个ClassA依赖于ClassB,然后ClassB又反过来依赖ClassA,这就形成了一个循环依赖: ClassA -> ClassB -> ClassA 原创声明 本 ...

  6. Spring如何解决循环依赖,你真的懂了?

    导读 前几天发表的文章SpringBoot多数据源动态切换和SpringBoot整合多数据源的巨坑中,提到了一个坑就是动态数据源添加@Primary接口就会造成循环依赖异常,如下图: 这个就是典型的构 ...

  7. Spring如何解决循环依赖?

    介绍 先说一下什么是循环依赖,Spring在初始化A的时候需要注入B,而初始化B的时候需要注入A,在Spring启动后这2个Bean都要被初始化完成 Spring的循环依赖有两种场景 构造器的循环依赖 ...

  8. 彻底理解Spring如何解决循环依赖

    Spring bean生命周期 可以简化为以下5步. 1.构建BeanDefinition 2.实例化 Instantiation 3.属性赋值 Populate 4.初始化 Initializati ...

  9. 【Spring】 Spring如何解决循环依赖的问题?

    https://mp.weixin.qq.com/s/FtbzTMxHgzL0G1R2pSlh-A 通常来说,如果问Spring内部如何解决循环依赖,一定是单默认的单例Bean中,属性互相引用的场景. ...

随机推荐

  1. HTML——标签使用

    一.CSS样式使用 title头下 <style type="text/css"> .divform /*样式名称*/{ position: absolute;/*绝对 ...

  2. 如何加入VNT Hubble主网

    环境:Ubuntu20.04 (但以下方法应该只要不是过于老旧的Ubuntu,都行得通) 从源码安装go-vnt 安装Go编译器(版本大于1.9)和C编译器 安装C编译器GCC[1] sudo apt ...

  3. nyoj-1236 挑战密室

    挑战密室 时间限制:1 s | 内存限制:128 M 提交 状态 排名 题目描述 R组织的特工Dr. Kong 为了寻找丢失的超体元素,不幸陷入WTO密室.Dr. Kong必须尽快找到解锁密码逃离,否 ...

  4. C# 类(3)

    方法重载 和python类似,在调用函数的时候可以指定默认参数,car("Jeep",color="red") 方法重载就是 可以定义几个同名的函数,然后带有不 ...

  5. spring-cloud-eureka-client-consumer

    服务注册中心eureka-server已经搭好,并且SPRING-CLOUD-NETFLIX-EUREKA-CLIENT-APPLICATION提供一个hello服务 编写一个eureka-clien ...

  6. springboot demo(一)快速开始

    快速入门 maven构建项目 1.访问http://start.spring.io/ 2.选择构建工具Maven Project.Spring Boot版本2.26以及一些工程基本信息,点击" ...

  7. canvas画布基本知识点总结

    HTML5的canvas元素使用JavaScript画图: <canvas width="600" height="400"> </canva ...

  8. Android四大组件简介:Android 基础知识,开发教程

    Android 四大组件: Activity.Service.Broadcast Receiver.Content Provider. http://developer.android.com/int ...

  9. node.js 怎么扩大默认的分配的最大运行内存

    node.js 怎么扩大默认的分配的最大运行内存 $ node --max-old-space-size=4096 app.js $ NODE_OPTIONS=--max-old-space-size ...

  10. JavaScript code 性能优化

    1 1 1 JavaScript 性能优化 prototype 闭包 Closure 内存泄漏 event system 1 定义类方法以下是低效的,因为每次构建baz.Bar的实例时,都会为foo创 ...