实现类:DefaultSingletonBeanRegistry
代码入口:AbstractBeanFactory#doGetBean
// 第一级 存放着经历了完整生命周期的bean
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 第三级 ObjectFactory 函数式接口,用于创建bean
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//第二级 存储着早期爆露的bean,Bean的生命周期未结束
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
spring 在创建 bean 之前,会将当前正在创建的 bean 名称放在一个列表中,这个列表我们就叫做 singletonsCurrentlyInCreation,用来记录正在创建中的 bean 名称列表,创建完毕之后,会将其从 singletonsCurrentlyInCreation 列表中移除,并且会将创建好的 bean 放到另外一个单例列表中,这个列表叫做 singletonObjects
判断循环依赖的源码在下面这个位置,singletonsCurrentlyInCreation是 Set 类型的,Set 的 add 方法返回 false,说明被 add 的元素在 Set 中已经存在了,然后会抛出循环依赖的异常
三级缓存解决循环依赖
AB循环依赖问题,只有A的注入方式是set,且是Singleton,就不会出现循环依赖问题
大致过程
关注四大方法 getSingleton() doCreateBean() populateBean() addSingleton()
- 调用doGetBean 方法获取beanA,getSingleton(beanName) 通过bean name在一级缓存中查找,查到返回,无则继续
- getSingleton(String beanName, ObjectFactory<?> singletonFactory),加入创建队列,调用createBean() 方法,从创建队列删除,加入一级缓存
- createBean()→doCreateBean(),如果单例、支持循环依赖、是否在创建队列中,都为true → 加入三级缓存[addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));]
- 进行属性填充,populateBean() ,发现依赖B,进行doGetBean(),发现缓存没有,创建,然后填充属性,调用getSingleton() 从三级缓存获取工厂,执行获取到A,于是B 顺利完成初始化,并将A 升级到 二级缓存
- 随后 beanA 继续它的 属性填充,此时也获得了B,beanA 也完成了 createBean() 创建,回到getSingleton()方法,继续执行,从创建队列删除,加入一级缓存