概述
我们在日常的技术交流中经常会提到Spring循环依赖,听起来挺高大尚的,那Spring到底是如何实现的呢?下面我们就来一一揭秘。
什么是循环依赖
如上图所示,A对象中包含B对象的引用,同时B对象中包含A对象的引用;也就是在创建A的过程中需要同时创建B对象,这就是所谓的循环依赖。
下面是普通对象创建的流程图,也正是循环依赖产生的根因。
可以看到A对象创建依赖B对象创建,B对象创建依赖A对象创建,形成了闭环,造成死循环了。
Spring三级缓存介绍
上图形成了一个闭环,如果想解决这个问题,那么就必须保证不会出现第二次创建A对象这个步骤,也就是说从容器中获取A的时候必须要能够获取到。
Spring中的如何解决的呢?
在Spring中,对象的创建可以分为实例化和初始化,实例化好但未完成初始化的对象是可以直接给其他对象引用的,所以此时可以做一件事,把完成实例化但未初始化的对象提前暴露出去,让其他对象能够进行引用,就完成了这个闭环的解环操作。
这就是常说的提前暴露对象。
spring中的三级缓存分别是什么
在spring源码的DefaultSingletonBeanRegistry.java类中
/**
* 一级缓存
* 用于保存beanName和创建bean实例之间的关系,是已经实例化和初始化完成的bean
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 二级缓存
* 用于保存beanName和创建bean实例之间的关系,与singletonObject的区别是这里面的bean是半成品,只完成实例化没有完成初始化;
* 与singletonFactories的区别是,当一个单例bean被放到这里之后,那么当bean还在创建过程中就可以通过getBean方法获取到,可以方便进行循环依赖的检测。
*/
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/**
* 三级缓存
* 用于保存beanName和和创建bean的工厂之间的关系,ObjectFactory就是一个Lambda表达式。
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16);