目录
- 问题介绍
- 什么是Spring中的三级缓存?
- Spring中的三级缓存是如何解决循环依赖问题的?
- 解决Spring循环依赖问题一定需要第三级缓存吗?
- 解决Spring循环依赖问题一定需要第二级缓存吗?
- 什么场景下的Spring循环依赖问题无法解决?
- 采用了构造器的注入方式
- 相互依赖的bean都是原型bean
- 采用@DependsOn注解而导致的循环依赖
- 使用了@Async注解
- 如何解决构造器注入的循环依赖?
- @Lazy是如何解决Spring循环依赖问题的?
问题介绍
注意这个问题与JVM中垃圾回收时的循环依赖问题进行区分。
JVM中垃圾回收时的循环依赖问题可以参考这篇博客中的垃圾回收部分。
Spring中的循环依赖问题是指IOC的加载过程当中bean创建的时候发生的,如下图所示,比如说当我们IOC加载创建BeanA的时候首先会去实例化A,然后进行属性注入解析@Autowired注解,发现依赖一个BeanB,这个时候会去IOC容器中帮我们去找BeanB,如果没有找到那么同样会先实例化B,然后进行属性注入解析@Autowired注解又发现依赖BeanA,这个时候又去IOC容器当中去拿BeanA,然后又没有拿到,又会去帮我们创建BeanA,就形成了一个闭环死循环。
答案:Spring则通过三级缓存来解决循环依赖问题。
循环典型的场景有以下三种:1.自我依赖。2.相互依赖。3.多个bean之间的依赖。比如A依赖B,B依赖C,…,而N又依赖A。
正常我们在创建Bean的时候完全可以通过先创建A和B两个对象的方法解决循环依赖,但是Spirng在创建非懒加载单例bean的时候出现循环依赖的问题是因为Spring的对象创建过程分为创建对象——实例化——属性填充三个过程。
什么是Spring中的三级缓存?
为了解决循环依赖问题,Spring 引入了三级缓存。那么,什么是 Spring 的三级缓存呢?首先,让我们看一下它们在DefaultSingletonBeanRegistry类中的定义,其实它们本质上就是一个Map。
—级缓存
一级缓存被命名为singletonObjects,也被称作单例池,它存储的是经历了完整的创建过程的单例 bean对象。一级缓存是一个ConcurrentHashMap,它的 key是String 类型,保存的是beanName; value 是Object 类型,保存的创建好的单例bean对象。
单例池并非专门用于解决Spring 的循环依赖问题,即便不考虑循环依赖,经历了Spring容器完整创建过程的单例 bean对象也会被放进该单例池。只不过在Spring解决循环依赖问题的三级缓存中被称为一级缓