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
  1. @DependsOn("b")
  2. @Component
  3. public class A {
  4. }
  5. @DependsOn("a")
  6. @Component
  7. public class B {
  8. }

报错:

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

源码解析

三级缓存

DefaultSingletonBeanRegistry类中:

  1. /** Cache of singleton objects: bean name to bean instance. */
  2. //一级缓存
  3. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  4. /** Cache of singleton factories: bean name to ObjectFactory. */
  5. //三级缓存
  6. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  7. /** Cache of early singleton objects: bean name to bean instance. */
  8. //二级缓存
  9. 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()方法中:

  1. if (!typeCheckOnly) {
  2. markBeanAsCreated(beanName);
  3. }

markBeanAsCreated方法中:

  1. this.alreadyCreated.add(beanName);

在getSingleton方法中,执行

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

其中singletonsCurrentlyInCreation为

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

在在getSingleton方法执行到

  1. singletonObject = singletonFactory.getObject();

调用匿名方法

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

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

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

bean(A)具备地址

A加入三级缓存singletonFactories中
  1. // Eagerly cache singletons to be able to resolve circular references
  2. // even when triggered by lifecycle interfaces like BeanFactoryAware.
  3. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  4. isSingletonCurrentlyInCreation(beanName));
  5. if (earlySingletonExposure) {
  6. if (logger.isTraceEnabled()) {
  7. logger.trace("Eagerly caching bean '" + beanName +
  8. "' to allow for resolving potential circular references");
  9. }
  10. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  11. }
  1. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  2. Assert.notNull(singletonFactory, "Singleton factory must not be null");
  3. synchronized (this.singletonObjects) {
  4. if (!this.singletonObjects.containsKey(beanName)) {
  5. this.singletonFactories.put(beanName, singletonFactory);
  6. this.earlySingletonObjects.remove(beanName);
  7. this.registeredSingletons.add(beanName);
  8. }
  9. }
  10. }
在populateBean方法中开始对A属性填充
  1. 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放到二级缓存中,并从三级缓存中移除

  1. Object sharedInstance = getSingleton(beanName);
  1. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  2. // Quick check for existing instance without full singleton lock
  3. Object singletonObject = this.singletonObjects.get(beanName);
  4. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  5. singletonObject = this.earlySingletonObjects.get(beanName);
  6. if (singletonObject == null && allowEarlyReference) {
  7. synchronized (this.singletonObjects) {
  8. // Consistent creation of early reference within full singleton lock
  9. singletonObject = this.singletonObjects.get(beanName);
  10. if (singletonObject == null) {
  11. singletonObject = this.earlySingletonObjects.get(beanName);
  12. if (singletonObject == null) {
  13. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  14. if (singletonFactory != null) {
  15. singletonObject = singletonFactory.getObject();
  16. this.earlySingletonObjects.put(beanName, singletonObject);
  17. this.singletonFactories.remove(beanName);
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }
  24. return singletonObject;
  25. }
B进行初始化

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

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

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

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

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

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

A开始执行下面代码:

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

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

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

面试问题

  • 一级缓存是否够用?

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

  • 二级缓存是否够用?

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

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

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

  1. /**
  2. * Obtain a reference for early access to the specified bean,
  3. * typically for the purpose of resolving a circular reference.
  4. * @param beanName the name of the bean (for error handling purposes)
  5. * @param mbd the merged bean definition for the bean
  6. * @param bean the raw bean instance
  7. * @return the object to expose as bean reference
  8. */
  9. protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
  10. Object exposedObject = bean;
  11. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  12. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  13. if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
  14. SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
  15. exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
  16. }
  17. }
  18. }
  19. return exposedObject;
  20. }

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. JAVA Schedule的Cron表达式

    spring中用到的定时任务,一般用到的有Timer()和Schedule Cron表达式一般是程序的定时任务中所要起的..我们用的springboot中的@Schedule中,启动类中添加enabl ...

  2. 为了运行十年前的代码,程序员们甚至翻出了一台 1977 年的 Apple II

    "Hello, World!" 46 年过去,这段被世人熟知的代码仍散发着历久弥新的魅力,和它一起登场的 C 语言,如今也成长为世界几大通行编程语言之一,为互联网世界乃至现实世界都 ...

  3. 【组合计数】visit

    题目大意 从 \((0,0)\) 开始,每次只可走上下左右一个单位长度,可走重复路,求第 \(T\) 步正好走到 \((n,m)\) 的方案数. 答案要求对 \(MOD\) 取模,\(MOD\) 保证 ...

  4. Archery安装教程

    一. CentOS设置 1. 更换阿里源 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos ...

  5. 从Linux源码看Socket(TCP)的listen及连接队列

    从Linux源码看Socket(TCP)的listen及连接队列 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就来从Linux源码的角度看 ...

  6. Jmeter入门(6)- 参数化

    一.什么是参数化 为什么要参数化? 在发送大量的请求时,键对值是写死的,每次请求都需要去修改,无法实现快速添加的需求.想要快速实现该需求,就需要用到参数化. 什么是参数化? 根据需求动态获取数据并进行 ...

  7. 如何使用FastCGI处理自定义HTTP头

    对于如何使用FastCGI处理自定义HTTP头这里记录一下注意事项: 在FastCGI中,自定义头可以从环境变量获得: 获取时名字前面要加HTTP_,字母要全部大写: 发送头不能有下划线_,否则该字段 ...

  8. java的回收机制

    在java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个: 1.给对象赋值为null,以下没有调用过. 2.给对象赋了新的值,重新分配了内存空间.

  9. 初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯

    初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯 前言 ​ 随着中美贸易战的加剧,很多公司越来越重视使用国产技术的重要性.使用国产技术,一方面可规避国外对技术的封锁造成产品核心 ...

  10. IDEA操作git的一些常用技巧

    转自:https://blog.csdn.net/ck4438707/article/details/53455962 Git原理以后会分章节介绍,本次主要说一下intellij怎样操作git.int ...