### 一、一级缓存(singletonObjects)
1. **作用**:存储已经完全初始化的单例Bean对象。
2. **数据结构**:一个Map<String, Object>,键是bean的名称,值是bean实例。
3. **说明**:当bean完全创建并初始化完成后,它就会被放入一级缓存中,表示该bean可供整个应用程序使用。
### 二、二级缓存(earlySingletonObjects)
1. **作用**:存储提前暴露的单例Bean,即在bean实例化过程中部分初始化好的对象。
2. **数据结构**:同样是一个Map<String, Object>,键是bean的名称,值是部分初始化的bean对象。
3. **说明**:在bean的创建过程中,如果某些依赖已经创建好并且可以提供给其他bean使用,这些尚未完全初始化的bean会被放入二级缓存中,以供后续使用。
### 三、三级缓存(singletonFactories)
1. **作用**:存储bean创建的工厂方法,即正在创建中的bean的工厂对象。
2. **数据结构**:一个Map<String, ObjectFactory<?>>,键是bean的名称,值是一个ObjectFactory实例,用于获取正在创建中的bean。
3. **说明**:当Spring遇到循环依赖问题,且目标bean尚未初始化时,它会将一个工厂方法放入三级缓存中。后续通过这个工厂方法来生成正在创建中的bean。
### 四、三级缓存如何解决循环依赖
Spring解决循环依赖的关键在于提前暴露和工厂方法的使用,具体流程如下:
1. **第一次实例化bean**:当Spring需要实例化一个bean时,会先检查该bean是否已经在一级缓存中。如果存在,则直接返回。如果不存在,则会开始创建这个bean。
2. **提前暴露部分初始化的bean**:在创建过程中,Spring会把已经部分初始化(例如构造函数已经调用完)的bean放入二级缓存中。这样,如果其他bean依赖于这个bean,能够获取到该bean的部分初始化实例(通常是一个代理对象)。
3. **循环依赖解决**:假设有bean A和bean B,A依赖B,而B又依赖A。Spring会先实例化A,并把A的工厂方法放入三级缓存中。此时,A还没有完全初始化,但它已经暴露出一个工厂方法,其他依赖它的bean(例如B)可以通过工厂方法获取到A的实例。当Spring需要初始化B时,发现B依赖A,而A尚未完全初始化。这时,Spring会通过三级缓存中的工厂方法获取到A的实例,由于A的工厂方法已经暴露,Spring能够获取到一个提前暴露的部分实例(此时A还未完全初始化,但足够满足B的依赖),然后继续初始化B。在B初始化完成后,Spring会继续完成A的初始化。
4. **最终完成初始化**:一旦A和B的循环依赖问题解决后,Spring会将它们完全初始化并放入一级缓存中。