循环依赖过程
A->B B->A

1、doGetBean->getSingleton(A)先从一级缓存单例缓存singletonObjects获取,这个时候为空,
再判断singletonObject == null && isSingletonCurrentlyInCreation(beanName)也不是正在创建单例,故而不能从二级缓存earlySingletonObjects获取

2、第二个获取单例getSingleton(A,createBean(beanName, mbd, args)),beforeSingletonCreation(beanName)把A放入singletonsCurrentlyInCreation缓存中

3、再执行createBean->doCreateBean->createBeanInstance(beanName, mbd, args)
先创建对象beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this)实例化对象执行构造函数

4、实例化对象后doCreateBean——>addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)),把A加入singletonFactories三级缓存中

5、然后doCreateBean -> populateBean(beanName, mbd, instanceWrapper)开始填充对象,这个时候发现有注入了B,然后要先实例化B,开始执行getBean

6、B重复动作1、2、3、发现要注入A,然后A再执行动作1,getSingleton(A)->singletonsCurrentlyInCreation有值然后把A放入二级缓存earlySingletonObjects中,
再把A从singletonFactories三级缓存删除。

7、A此时完成二级缓存earlySingletonObjects中半成本,返回给B,populateBean填充完属性,执行initializeBean初始化对象B,
执行applyBeanPostProcessorsBeforeInitialization(),invokeInitMethods(),applyBeanPostProcessorsAfterInitialization()三部曲,然后完成B的初始化
最后addSingleton()把B加入singletonObjects单例池中,把B从二级缓存earlySingletonObjects删除

8、然后主程序回到A执行的5中,完成了B的填充,A执行initializeBean初始化对象,
执行applyBeanPostProcessorsBeforeInitialization(),invokeInitMethods(),applyBeanPostProcessorsAfterInitialization()三部曲,然后完成B的初始化
最后addSingleton()把A加入singletonObjects单例池中,把A从二级缓存earlySingletonObjects删除

总结:
A->B B->A 过程是: A实例化->B实例化->B初始化->A初始化
1、一级缓存singletonObjects单例池,对象完成初始化时放入
2、二级缓存earlySingletonObjects半成品,提前暴露对象
3、三级缓存singletonFactories,解决循环依赖主要作用

实例化A -> A加入singletonFactories三级缓存中 -> 填充A,发现要注入B ->
实例化B -> B加入singletonFactories三级缓存中 -> 填充B,发现要注入A -> 创建中A加入earlySingletonObjects二级缓存,删除singletonFactories,返回半成品 ->
B拿到A半成品,initializeBean初始化对象 -> B初始化完成 -> B放入singletonObjects单例池,删除earlySingletonObjects
A拿到实例化的B,initializeBean初始化对象 -> A初始化完成 -> A放入singletonObjects单例池,删除earlySingletonObjects

在这个过程中发现B并没有生成earlySingletonObjects二级缓存,主要作用还是singletonFactories三级缓存。

@PostConstruct 、implements InitializingBean、xml配置init-mthon方法,执行顺序是@PostConstruct、InitializingBean、xml 取决代码执行initializeBean初始化对象,
执行applyBeanPostProcessorsBeforeInitialization(),invokeInitMethods(),applyBeanPostProcessorsAfterInitialization()三部曲

spring循环依赖过程的更多相关文章

  1. 3.3 Spring5源码---循环依赖过程中spring读取不完整bean的最终解决方案

    根据之前解析的循环依赖的源码, 分析了一级缓存,二级缓存,三级缓存的作用以及如何解决循环依赖的. 然而在多线程的情况下, Spring在创建bean的过程中, 可能会读取到不完整的bean. 下面, ...

  2. Spring 循环依赖

    循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...

  3. Springboot源码分析之Spring循环依赖揭秘

    摘要: 若你是一个有经验的程序员,那你在开发中必然碰到过这种现象:事务不生效.或许刚说到这,有的小伙伴就会大惊失色了.Spring不是解决了循环依赖问题吗,它是怎么又会发生循环依赖的呢?,接下来就让我 ...

  4. Spring 循环依赖的三种方式(三级缓存解决Set循环依赖问题)

    本篇文章解决以下问题: [1] . Spring循环依赖指的是什么? [2] . Spring能解决哪种情况的循环依赖?不能解决哪种情况? [3] . Spring能解决的循环依赖原理(三级缓存) 一 ...

  5. Spring循环依赖的解决

    ## Spring循环依赖的解决 ### 什么是循环依赖 循环依赖,是依赖关系形成了一个圆环.比如:A对象有一个属性B,那么这时候我们称之为A依赖B,如果这时候B对象里面有一个属性A.那么这时候A和B ...

  6. 这个 Spring 循环依赖的坑,90% 以上的人都不知道

    1. 前言 这两天工作遇到了一个挺有意思的Spring循环依赖的问题,但是这个和以往遇到的循环依赖问题都不太一样,隐藏的相当隐蔽,网络上也很少看到有其他人遇到类似的问题.这里权且称他非典型Spring ...

  7. Spring — 循环依赖

    读完这篇文章你将会收获到 Spring 循环依赖可以分为哪两种 Spring 如何解决 setter 循环依赖 Spring 为何是三级缓存 , 二级不行 ? Spring 为啥不能解决构造器循环依赖 ...

  8. spring 循环依赖的一次 理解

    前言: 在看spring 循环依赖的问题中,知道原理,网上一堆的资料有讲原理. 但今天在看代码过程中,又产生了疑问. 疑问点如下: // 疑问点: 先进行 dependon 判断String[] de ...

  9. 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖

    本次博客的目标 1. 手写spring循环依赖的整个过程 2. spring怎么解决循环依赖 3. 为什么要二级缓存和三级缓存 4. spring有没有解决构造函数的循环依赖 5. spring有没有 ...

  10. Spring循环依赖原理

    Spring循环依赖的原理解析 1.什么是循环依赖? ​ 我们使用Spring的时候,在一个对象中注入另一个对象,但是另外的一个对象中也包含该对象.如图: 在Student中包含了teacher的一个 ...

随机推荐

  1. 集成Unity3D到iOS应用程序中

    如果想让原生平台(例如 Java/Android.Objective C/iOS 或 Windows Win32/UWP)包含 Unity 功能,可以通过Unity 生成UnityFramework静 ...

  2. Docker从认识到实践再到底层原理(二-1)|容器技术发展史+虚拟化容器概念和简介

    前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...

  3. Collectors.toMap的暗坑与避免方式

    使用Java的stream中的Collectors可以很方便地做容器间的转换,可以少写很多代码.但是其中有暗含的坑需要注意和避免,本文探讨Collectors.toMap(JDK8版本). Colle ...

  4. Pandas 人口密度案例分析

    from turtle import left import pandas as pd """ 需求: 1.导入文件,查看原始数据 2.将人口数据和各州简称数据进行合并 ...

  5. JS 保姆级贴心,从零教你手写实现一个防抖debounce方法

    壹 ❀ 引 防抖在前端开发中算一个基础但很实用的开发技巧,在对于一些高频操作例如监听输入框值变化触发更新之类,会有奇效.除了实际开发,在面试中我们也可能偶遇手写防抖节流的问题,鉴于不同公司考核要求不一 ...

  6. JS leetcode 移除元素 题解分析

    壹 ❀ 引 又到了每日一道算法题的环节,今天做的题同样非常简单,题目来源leetcode27. 移除元素,题目描述如下: 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 va ...

  7. Linux下磁盘管理工具:hdparm/iostat/parted/fdiisk/badblocks/smartctl/losetup/sg3_utils/sqinfo/smp_utils/udevadm

    一.hdparm:       hdparm可以检测,显示与设定IDE,SCSI,SATA,SAS硬盘的硬件参数,       如: hdparm -I /dev/sdc 可以获取sdc的硬件信息  ...

  8. phpBB3在Nginx反向代理中的X-Forwarded-For IP检查

    记录一下phpBB3对反向代理中的IP处理机制 处理几个phpBB3项目迁移, 部分运行场景转移到内网, 需要外网通过nginx/openresty之类的网关反向代理进行访问. 在网关处已经正确配置了 ...

  9. Python中文件读写操作

    1 txt文件 1.1 写操作 import numpy as np def write(fileName,data): file=open(fileName,'w') row,col=data.sh ...

  10. 易语言读取Mysql表数据

    源码下载: https://download.csdn.net/download/IndexMan/12029860 1.界面设计 2.效果展示 3.源码展示 程序集变量: 读取数据按钮: 读取数据子 ...