Spring如何使用三级缓存解决循环依赖

首先来了解一下什么是循环依赖

@Component
public class A { @Autowired
B b;
} @Component
public class B { @Autowired
A a;
}

在对象A创建过程中,需要注入B,因为容器中没有B,则去创建B,B创建过程中又需要注入A,而A在等待B的创建,B在等待A的创建,导致两者都无法创建成功,无法加入到单例池供用户使用。

Spring则通过三级缓存来解决循环依赖的问题,另外如果对象的作用范围是Prototype,则无法通过三级缓存解决循环依赖,会抛出BeanCurrentlyInCreationException异常,构造注入的方式,也无法解决循环依赖,只有set注入可以解决。

那么三级缓存又是什么呢?

三级缓存就是三个Map

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	//一级缓存(单例池,经过完成生命周期的对象会放入其中)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //二级缓存(刚实例化还未初始化的原始对象会放入其中)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); //三级缓存(存放创建某个对象的工厂)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

Spring Bean对象从创建到初始化大致会经过四个流程

getSingleton()doCreateBean()populateBean()addSingleton()

  • getSingleton:从单例池中获取bean对象,如果没有,则进行创建

  • doCreateBean():创建bean对象

  • populateBean():填充依赖,如果被填充的对象不存在于单例池,则进行创建等四个流程

  • addSingleton():将初始化完成的对象加入到单例池

循环依赖的对象在三级缓存中的迁移过程

  • A 创建过程中需要 B, 于是 A 将自己放到三级缓存里面,去实例化 B

  • B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存

    找到了A,然后把三级缓存中的 A 放到二级缓存,并删除三级缓存中的 A

  • B 顺利初始化完毕,将自己放到一级缓存中(此时 B 中的 A 还是创建中状态,并没有完全初始化),删除三级缓存中的 B

    然后接着回来创建 A,此时 B 已经完成创建,直接从一级缓存中拿到 B,完成 A 的创建,并将 A 添加到单例池,删除二级缓存中的 A

图示:

Spring如何使用三级缓存解决循环依赖的更多相关文章

  1. Spring三级缓存解决循环依赖

    前提知识 1.解决循环依赖的核心依据:实例化和初始化步骤是分开执行的 2.实现方式:三级缓存 3.lambda表达式的延迟执行特性 spring源码执行逻辑 核心方法refresh(), popula ...

  2. Spring ioc(4)---如何解决循环依赖

    前面说到对象的创建,那么在创建的过程中Spring是怎么又是如何解决循环依赖的呢.前面提到有个三级缓存.就是利用这个来解决循环依赖.打个比方说实例化A的时候,先将A创建(早期对象)放入一个池子中.这个 ...

  3. spring: 我是如何解决循环依赖的?

    1.由同事抛的一个问题开始 最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到.平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的 ...

  4. 曹工说Spring Boot源码(29)-- Spring 解决循环依赖为什么使用三级缓存,而不是二级缓存

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  5. Spring 动态代理时是如何解决循环依赖的?为什么要使用三级缓存?

    前言 在研究 『 Spring 是如何解决循环依赖的 』 的时候,了解到 Spring 是借助三级缓存来解决循环依赖的. 同样在上一节留下了疑问: 循环依赖为什么要使用三级缓存?而不是使用二级缓存? ...

  6. Spring如何解决循环依赖问题

    目录 1. 什么是循环依赖? 2. 怎么检测是否存在循环依赖 3. Spring怎么解决循环依赖 本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可 ...

  7. Spring解决循环依赖,你真的懂了吗?

    导读 前几天发表的文章SpringBoot多数据源动态切换和SpringBoot整合多数据源的巨坑中,提到了一个坑就是动态数据源添加@Primary接口就会造成循环依赖异常,如下图: 这个就是典型的构 ...

  8. Spring如何解决循环依赖,你真的懂了?

    导读 前几天发表的文章SpringBoot多数据源动态切换和SpringBoot整合多数据源的巨坑中,提到了一个坑就是动态数据源添加@Primary接口就会造成循环依赖异常,如下图: 这个就是典型的构 ...

  9. Spring是如何解决循环依赖的

    前言 在面试的时候这两年有一个非常高频的关于spring的问题,那就是spring是如何解决循环依赖的.这个问题听着就是轻描淡写的一句话,其实考察的内容还是非常多的,主要还是考察的应聘者有没有研究过s ...

随机推荐

  1. 设计模式-UML图简单介绍

    直接上法宝: 1.类(Class)     类图分三层:     第一层显示类的名称,如果是抽象类,则就用斜体显示.     第二层是类的特性,通常就是字段和属性.     第三层是类的操作,通常是方 ...

  2. xposed学习四:总结

    xposed的学习要告一段落,接下来去学习android apk和so加固,这里我们回顾下xposed吧. xposed是个hook框架,它是基于dalvik(确切来说是目前的版本,作者说ART也快出 ...

  3. Docker安装和helloworld

    0.基本简介(想直接实操,直接跳过去看1就好) Docker 在容器的基础上,进行了进一步的封装,从文件系统.网络互联到进程隔离等等,极大的简化了容器的创建和维护.使得 Docker 技术比虚拟机技术 ...

  4. JVM垃圾回收器总结

    常见七种垃圾回收器以及使用的垃圾回收算法总结:

  5. Linux下线程pid和tid

    #include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/sy ...

  6. UVa OJ 455 Periodic Strings

     Periodic Strings  A character string is said to have period k if it can be formed by concatenating ...

  7. BUAA-OO-第四单元总结——终章

    面向对象第四单元博客总结--终章 第四单元作业设计 第13次作业设计 类和对应方法属性设计 类设计如下图所示 本次作业主要涉及六个类,其中包括主类 Main ,通用Map类 UmlElementIdM ...

  8. 聊一聊 JVM 的 GC

    原文链接:https://www.changxuan.top/?p=1457 引言 JVM 中的 GC 在技术博客中应该算是个老生常谈的话题,网络上也存在着许多质量参差不齐的文章,可以看出来大都是&q ...

  9. [Python] 基本概念

    1.基本概念 三大特性:封装.继承.多态 继承:派生类继承基类的字段和方法 多态:对不同类型的变量进行相同的操作,却表现出不同的行为(例如对数字和字符做"+"运算) 封装:将数据和 ...

  10. 运维实战案例之“Too many open files”错误与解决方法

    运维实战案例之"Too many open files"错误与解决方法   技术小甜 2017-11-16 15:02:00 浏览869 服务器 shell tomcat 脚本 o ...