spring容器中解决循环依赖问题的机制主要包括三级缓存(三级map)的概念。这三级缓存用于存储正在创建的bean实例。它们分别是singletonObjects、earlySingletonObjects和singletonFectories。
三级缓存介绍:
1、singletonObjects:存储完全初始化的singleton bean实例,即所有依赖都已经解析完成,bean已经可以使用。在这个缓存中,通过map进行缓存,k是bean的名称,value是bean的实例。
2、earlySingletonObjects:存储早期暴露的singleton bean实例,即bean的依赖关系已经解析,但bean的初始化尚未完成。在这个缓存中,通过map进行缓存,k是bean的名称,value是bean的实例。
3、singletonFactories:存储singleton bean的ObjectFactory,即用于创建bean实例的工厂对象
spring检查bean缓存的流程:
SingletonObjects --> EarlySingletonObjects --> SingletonFactory,检查每级缓存,如果存在所需的bean就返回,否则就继续向下层级检查。检查到最后一级singletonFactory缓存中如果存在,则执行factory.get()方法获取一个earlySingletonObjects,如果不存在则创建一个所需对象的factory。
假设A类依赖B,同时B类依赖A类,起初创建A类的bean发现前两个缓存中都没有,如果A类满足单例且允许循环依赖,那么此时会在singletonFactory中创建一个A类的factory,那么在下次循环按层级检查缓存的时候就会找到该factory从而利用该factory创建earlySingletonObject。
以下是Spring容器解决循环依赖的大致流程:
- 当容器创建一个bean时,首先检查singletonObjects缓存。如果缓存中有该bean的实例,直接返回。
- 如果singletonObjects缓存中没有该bean的实例,继续检查earlySingletonObjects缓存。如果在earlySingletonObjects中找到该bean的实例,则将其返回。这表示该bean已经被创建,但尚未完全初始化。
- 如果以上两个缓存都没有,表示该bean是第一次创建。容器会创建一个singletonFactories中存储的ObjectFactory,并调用该工厂的getObject()方法创建bean实例。
- 在创建bean实例的过程中,如果发现有其他bean引用了正在创建的bean(循环依赖),则容器会提前暴露earlySingletonObjects缓存中的实例,使得引用可以得到一个早期的实例。
- 当bean的所有依赖都已经解析完成,bean实例完全初始化后,将其存储到singletonObjects缓存中,清除earlySingletonObjects缓存中的实例,最后返回该bean实例。