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的文章多如牛毛,为什么还要写呢,因为,很简单,那是人家写的:网上都鼓励你不要造轮子,为什么你还要造呢,因为,那不是你造的. 我不是要 ...
随机推荐
- how to convert wstring to string
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <local ...
- vagrant相关
无法挂载共享目录,报错如下 Vagrant was unable to mount VirtualBox shared folders. This is usually because the fil ...
- 网络最大流(EK)
以前在oi中见到网络流的题都是直接跳过,由于本蒟蒻的理解能力太弱,导致网络流的学习不断推迟甚至被安排在了tarjan之后,原本计划于学习完最短路后就来学网络流的想法也随之破灭,在看完众多大佬 的博客后 ...
- learn about sqlserver partitition and partition table --- add or remove table partitions
demo/* add partitions */ alter database xxx add filegroup FG_=fff_201708;alter database xxx add file ...
- MongoDB疑难解析:为什么升级之后负载升高了?
本文是"我和MongoDB的故事"征文比赛的二等奖得主李鹏冲的文章.下面我们一起来欣赏下. 问题 近期线上一个三分片集群从 3.2 版本升级到 4.0 版本以后,集群节点的 CPU ...
- 使用Python打造一款间谍程序
知识点 这次我们使用python来打造一款间谍程序 程序中会用到许多知识点,大致分为四块 win32API 此处可以在MSDN上查看 Python基础重点在cpytes库的使用,使用方法请点击此处 ...
- 《Head first设计模式》之模版方法模式
模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 有些人没有咖啡就活不下去:有些人则离不开茶.两者共同的 ...
- qt creator源码全方面分析(2-3-2)
目录 Showing Task List Files in Issues Pane 管理任务列表条目 任务列表文件格式 Showing Task List Files in Issues Pane 您 ...
- Angular常用命令
一. Angular常用命令 1. ng new 文件夹名 (新建项目,选择y使用路由) 2. ng serve --open (默认浏览器运行项目) 3. ng serve --port 6060 ...
- Java的引用类型的内存分析
一. jdk的内存:jdk的bin目录常见命令 1. javac.exe:编译java源代码的,生成java字节码文件(*.class) 2. java.exe:启动一个jvm,来运行指定class字 ...