Spring Boot源码(七):循环依赖
循环依赖
以及
spring是如何解决循环依赖的
循环依赖
通俗来说
就是beanA中依赖了beanB,beanB中也依赖了beanA。
spring是支持循环依赖的,但是默认只支持单例的循环依赖,如果bean中依赖了原型bean,则需要加上lookup方法。
继续之前的项目,改造了People,User类:
@Component
public class People {
@Autowired
private User user;
public People(){
System.out.println("create People");
}
}
@Component
public class User {
@Autowired
private People people;
public User(){
System.out.println("create User");
}
}
People--(依赖)-->User--(依赖)-->People--(依赖)-->User.......,这就形成了循环依赖。
继续进入上篇的preInstantiateSingletons()方法:

进行条件断点:


进入上篇说的getSingleTon()方法:

singletonObjects是spring的单例池,从其中没有拿到bean,singletonObject为null,且isSingletonCurrentlyInCreation()为false。
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
其实这个方法就是去判断该map(singletonCurrentlyInCreation)是否包含该bean?(这里是people)。
这个方法通俗意思就是 “该bean是否在创建过程中?”
先不管这个意思,继续往下走。
spring创建对象前还会做很多判断,例如是否为原型,是否抽象?

这里的getSingleton(String beanName, ObjectFactory<?> singletonFactory)是重载,与之前的getSingleton(String beanName, boolean allowEarlyReference)不同。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
此方法把 “people”放入singletonsCurrentlyInCreation中,那么isSingletonCurrentlyInCreation("people")这时为true。

进入lambda表达式 createBean()
create People Object ----注入依赖发现依赖User--->create User Object---发现依赖People---create People Object---发现isSingletonCurrentlyInCreation(beanName)为true,表示正在创建People:

然后才会执行里面的代码:

allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象,也就是执行if中的方法。
我们看一下singletonObjects(一级缓存),earlySingletonObjects(二级缓存),singletonFactories(三级缓存)。
AbstractAutowireCapableBeanFactory#doCreateBean()中:


这时候存进去的并不是完整的bean:

但是可以供User依赖注入了,这也就是spring对循环依赖的解决。
Spring Boot源码(七):循环依赖的更多相关文章
- 曹工说Spring Boot源码(29)-- Spring 解决循环依赖为什么使用三级缓存,而不是二级缓存
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- Spring IOC 容器源码分析 - 循环依赖的解决办法
1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...
- 曹工说Spring Boot源码(22)-- 你说我Spring Aop依赖AspectJ,我依赖它什么了
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- Spring Boot源码(六):Bean的创建详解
继续之前的项目: People加上无参构造方法: @Component public class People { // private User user; public People(){ Sys ...
- 曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(23)-- ASM又立功了,Spring原来是这么递归获取注解的元注解的
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎
曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎 写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean De ...
- 曹工说Spring Boot源码(27)-- Spring的component-scan,光是include-filter属性的各种配置方式,就够玩半天了.md
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(30)-- ConfigurationClassPostProcessor 实在太硬核了,为了了解它,我可能debug了快一天
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享
写在前面的话&&About me 网上写spring的文章多如牛毛,为什么还要写呢,因为,很简单,那是人家写的:网上都鼓励你不要造轮子,为什么你还要造呢,因为,那不是你造的. 我不是要 ...
随机推荐
- nginx命令行及演示:重载、热部署、日志切割
重载配置文件 nginx -s reload 热部署(升级nginx) 首先备份二进制文件 cp nginx nginx.old 拷贝新版本的nginx替换以前的nginx二进制文件 cp ngi ...
- Windows下SVN权限配置
Windows下SVN权限配置 按照前面的教程装完1.6.1版以后,当svnadmin create D;\svn创建仓库后,应该在仓库目录下的config目录有3个文件— auth ...
- web通信类几个相关知识
1.什么是同源策略及限制? 同源策略限制从一个源加载的文档或者脚本如何与来自另一个源的资源进行交互. 这是一个用于隔离潜在恶意文件的关键安全机制. 所谓同源,就是指两个页面具有相同的协议,主机(也常说 ...
- Java中的8种基本数据类型
JAVA中的8种基本数据类型:byte short int long float double char boolean 特别说明: 1)char类型占2个字节,可以表示汉字.汉字和英文字符都占2个字 ...
- pyspark 记录
import os import sys spark_name = os.environ.get('SPARK_HOME',None) if not spark_name: raise ValueEr ...
- 介绍求解AX=b:可解性与解的结构
前面用高斯消元法或矩阵LU分解求解线性方程组的解,主要是针对有唯一解(矩阵A可逆)的情况,下面进一步介绍线性方程组有多个解的情况下,解的求解.
- golang的timer一些坑
本文代码部分基于dive-to-gosync-workshop的代码 Golang 的NewTimer方法调用后,生成的timer会放入最小堆,一个后台goroutine会扫描这个堆,将到时的time ...
- Spring ioc(4)---如何解决循环依赖
前面说到对象的创建,那么在创建的过程中Spring是怎么又是如何解决循环依赖的呢.前面提到有个三级缓存.就是利用这个来解决循环依赖.打个比方说实例化A的时候,先将A创建(早期对象)放入一个池子中.这个 ...
- uniapp简易直播
实验准备 在服务器部署nginx-rtmp作为我们直播推流和拉流的服务器(如果服务商选择七牛,也是直接给地址推流).为了加快部署,我在这一步使用Docker. docker pull tiangolo ...
- web渗透之XSS基本介绍
想学XSS必须得有基本得JS知识 JS基础BOM XSS漏洞原理 XSS(Cross Site Script),全称跨站脚本攻击.它指的是攻击者往web页面或者url里插入恶意JavaScript脚本 ...