https://www.cnblogs.com/longy2012/articles/12834762.html

https://www.bilibili.com/video/BV1iD4y1o7pM?p=7

https://www.jianshu.com/p/8bb67ca11831

https://cloud.tencent.com/developer/article/1497692

https://blog.nowcoder.net/n/2bb528b258b44c7eab1703a52170ef09

总结

  1. 在DefaultSingletonBeanRegistry类getSingleton方法中将beanName(a)加入到singletonsCurrentlyInCreation set集合中
  2. A进行实例化(未初始化)
  3. A加入三级缓存singletonFactories中
  4. 在AbstractAutowireCapableBeanFactory中populateBean方法中开始属性填充(field B)(调用AutowiredAnnotationBeanPostProcessor类中postProcessProperties方法)
  5. 在DefaultSingletonBeanRegistry类getSingleton方法中将beanName(b)加入到singletonsCurrentlyInCreation set集合中
  6. 将B加入singletonsCurrentlyInCreation,标志为正在创建中
  7. B进行实例化(未初始化)
  8. B加入三级缓存singletonFactories中
  9. 开始对B类进行属性填充(A field)
  10. 重新走到AbstractBeanFactory中doGetBean方法,调用DefaultSingletonBeanRegistry类getSingleton方法,将A put到二级缓存earlySingletonObjects中,并在三级缓存singletonFactories中移除
  11. B进行初始化
  12. getSingleton方法中调用DefaultSingletonBeanRegistry类afterSingletonCreation方法,将beanName(b)从singletonsCurrentlyInCreation移除
  13. 走到DefaultSingletonBeanRegistry中getSingleton方法finally中,将B加入一级缓存,并从三级缓存中移除
  14. 将B返回,A进行初始化
  15. getSingleton方法中调用DefaultSingletonBeanRegistry类afterSingletonCreation方法,将beanName(a)从singletonsCurrentlyInCreation移除
  16. 最后走到DefaultSingletonBeanRegistry中getSingleton方法finally中,将A加入一级缓存,并从二级缓存中移除

示例

  1. @DependsOn
@DependsOn("b")
@Component
public class A {
} @DependsOn("a")
@Component
public class B {
}

报错:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined
  1. field属性注入循环依赖(不报错)
@Component
public class A {
@Autowired
private B b;
} @Component
public class B {
@Autowired
private A a;
}

源码解析

三级缓存

DefaultSingletonBeanRegistry类中:

	/** Cache of singleton objects: bean name to bean instance. */
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */
//三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */
//二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
springboot中入口

调用链:

SpringApplication#run() --> SpringApplication#refreshContext() --> SpringApplication#refresh() --> ServletWebServerApplicationContext#refresh() --> AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean()

将beanName(a)加入到singletonsCurrentlyInCreation

AbstractBeanFactory#doGetBean()方法中:

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

markBeanAsCreated方法中:

this.alreadyCreated.add(beanName);

在getSingleton方法中,执行

beforeSingletonCreation(beanName);
this.singletonsCurrentlyInCreation.add(beanName)

其中singletonsCurrentlyInCreation为

/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
A进行实例化(未初始化)

在在getSingleton方法执行到

singletonObject = singletonFactory.getObject();

调用匿名方法

() -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}

调用AbstractAutowireCapableBeanFactory#createBean() --> AbstractAutowireCapableBeanFactory#doCreateBean(),执行如下代码进行实例化:

if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();

bean(A)具备地址

A加入三级缓存singletonFactories中
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
在populateBean方法中开始对A属性填充
populateBean(beanName, mbd, instanceWrapper);
对B重复上面步骤

调用链

AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean() --> AbstractAutowireCapableBeanFactory#createBean()

--> AbstractAutowireCapableBeanFactory#doCreateBean()

(上面为A,下面开始A属性B注入)

--> AbstractAutowireCapableBeanFactory#populateBean() --> AutowiredAnnotationBeanPostProcessor#postProcessProperties() --> InjectionMetadata#inject() --> AutowiredAnnotationBeanPostProcessor#inject() --> DefaultListableBeanFactory#resolveDependency() --> DefaultListableBeanFactory#doResolveDependency() --> DependencyDescriptor#resolveCandidate() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean()

会和上面A同样做下面这些操作:

  • 在DefaultSingletonBeanRegistry类getSingleton方法中将beanName(b)加入到singletonsCurrentlyInCreation set集合中
  • 将B加入singletonsCurrentlyInCreation,标志为正在创建中
  • B进行实例化(未初始化,具有B地址)
  • B加入三级缓存singletonFactories中
  • 开始对B类进行属性填充(A field)
将A put到二级缓存earlySingletonObjects中

重新对A执行doGetBean方法,执行getSingleton时,singletonFactory != null,故A放到二级缓存中,并从三级缓存中移除

Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
B进行初始化

此时B完成属性注入,A具有地址,开始初始化:

// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
将beanName(b)从singletonsCurrentlyInCreation移除

B执行完AbstractBeanFactory类匿名方法中createBean(beanName, mbd, args),接着getSingleton往下执行,在finally中:

finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
将B加入一级缓存,并从三级缓存中移除

在getSingleton方法执行addSingleton(beanName, singletonObject);从而将B从三级缓存中移除,并添加到一级缓存中

protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
完成A中B属性注入,对A进行初始化

A开始执行下面代码:

exposedObject = initializeBean(beanName, exposedObject, mbd);
开始将beanName(a)从singletonsCurrentlyInCreation移除;并从二级缓存中移除,添加到一级缓存

A接着getSingleton往下执行,在finally中执行afterSingletonCreation将beanName(a)从singletonsCurrentlyInCreation移除;

最后在addSingleton(beanName, singletonObject)将A从二级缓存中移除,添加到一级缓存

面试问题

  • 一级缓存是否够用?

不能。多线程情况下,会获取到实例化但没有初始化的对象,属性都为null

  • 二级缓存是否够用?

如果创建是普通类,二级缓存满足

  • 为什么需要三级缓存?(代理)

在动态代理中,返回是代理类。如果没有三级缓存,最开始放置是实例化好对象,然后缓存有了,后面进行代理处理,那原来的对象是否覆盖??

	/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}

Spring源码之循环依赖的更多相关文章

  1. Spring源码解析——循环依赖的解决方案

    一.前言 承接<Spring源码解析--创建bean>.<Spring源码解析--创建bean的实例>,我们今天接着聊聊,循环依赖的解决方案,即创建bean的ObjectFac ...

  2. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  3. 3.2spring源码系列----循环依赖源码分析

    首先,我们在3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖 中手写了循环依赖的实现. 这个实现就是模拟的spring的循环依赖. 目的是为了更容易理解spring源码 ...

  4. 3.4 spring5源码系列--循环依赖的设计思想

    前面已经写了关于三篇循环依赖的文章, 这是一个总结篇 第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖 第二篇: 3.2spring源码系列----循环依赖源 ...

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

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

  6. 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析

    目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...

  7. 【Spring源码解析】—— 依赖注入结合SpringMVC Demo-xml配置理解

    在IOC容器初始化的梳理之后,对依赖注入做一个总结,就是bean实例化的过程,bean的定义有两种方式,一种是xml文件配置,一种是注解,这里是对xml配置文件的依赖注入的介绍,后续对bean与该部分 ...

  8. Spring源码-循环依赖源码解读

    Spring源码-循环依赖源码解读 笔者最近无论是看书还是从网上找资料,都没发现对Spring源码是怎么解决循环依赖这一问题的详解,大家都是解释了Spring解决循环依赖的想法(有的解释也不准确,在& ...

  9. Spring源码分析(十七)循环依赖

    本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 实例化bean是一个非常复杂的过程,而其中比较难以理解的就是对循环依赖的解决, ...

随机推荐

  1. kubernetes:用kubeadm管理token(kubernetes 1.18.3)

    一,token的用途: 1,token是node节点用来连接master节点的令牌字串, 它和ca证书的hash值是把一台node节点加入到kubernetes集群时要使用的凭证 2, 通过kubea ...

  2. centos8上安装mysql8

    一,下载并解压mysql8 1,mysql官网 https://www.mysql.com/ 2,下载到source目录 [root@yjweb source]# wget https://cdn.m ...

  3. linux 压缩 tar命令

    linux中tar命令用法    总结 *.tar 用 tar –xvf 解压 *.gz 用 gzip -d或者gunzip 解压 *.tar.gz和*.tgz 用 tar –xzf 解压 *.bz2 ...

  4. pychartdir模块安装

    python模块pychartdir导入问题 在迁移别人写好的脚本时,发现pychartdir没有导入,脚本执行报错.以下是报错内容: [modps@LGJF-ZYC5-MMSC-WEB02 ~]$ ...

  5. 阿里云ECS磁盘扩容不生效处理办法

    原因 阿里云ECS云盘扩容后,在Linux服务器上没有生效 实际需要几条命令扩容才能正式生效. 处理方法 先看扩容前磁盘空间,/dev/vda1可以看到只有40G. # df -Th Filesyst ...

  6. OpenCV计算机视觉学习(8)——图像轮廓处理(轮廓绘制,轮廓检索,轮廓填充,轮廓近似)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 1, ...

  7. 数位dp(贴一个模板=。=)

    emmmm,之前看到大佬的博客感觉这个模板挺有用的,就贴了一个= = 然后解释什么的都有了就...... 数位dp一般应用于: 求出在给定区间[A,B]内,符合条件P(i)的数i的个数. 条件P(i) ...

  8. vue 404

    问题描述:前端同事使用Vue.js框架,利用vue-route结合webpack编写了一个单页路由项目,运维协助在服务器端配置nginx.部署完成后,访问首页没问题,从首页里打开二级页面没问题,但是所 ...

  9. D. Kilani and the Game 解析(裸BFS、實作)

    Codeforce 1105 D. Kilani and the Game 解析(裸BFS.實作) 今天我們來看看CF1105D 題目連結 題目 給一個\(n\times m\)的地圖,地圖上有幾種格 ...

  10. E. Median String 解析(思維、大數運算)

    Codeforce 1144 E. Median String 解析(思維.大數運算) 今天我們來看看CF1144E 題目連結 題目 給你兩個長度為\(k\)的字串\(s\)和\(t\),求字典序排序 ...