CS-Base icon indicating copy to clipboard operation
CS-Base copied to clipboard

Spring通过三级缓存解决单例模式循环依赖的步骤好像是错的

Open iamarealgoodman opened this issue 5 months ago • 0 comments

Spring通过三级缓存解决单例模式循环依赖的步骤好像是错的,好像应该是:

在 Spring 容器中,三级缓存机制用于解决单例模式下 bean 的循环依赖问题。以下是三级缓存解决循环依赖的详细流程:

1. 创建 bean 实例

当 Spring 容器开始创建一个 bean 时,首先会通过反射创建一个原始的 bean 实例。

2. 将 bean 实例放入三级缓存

在创建完原始 bean 实例后,Spring 容器会立即将这个实例包装成一个 ObjectFactory,并将其放入三级缓存(singletonFactories)中。ObjectFactory 是一个工厂对象,它能够提供 bean 的早期引用。

singletonFactories.put(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

3. 填充属性

Spring 尝试为这个原始的 bean 实例填充属性,如果此时发现依赖的属性还未创建,则会尝试创建依赖的 bean。

4. 检查依赖的 bean 是否已经创建

在创建依赖的 bean 时,Spring 容器会重复上述步骤。如果在创建依赖 bean 的过程中又需要依赖原始的 bean,则会触发以下流程:

5. 检查一级缓存

Spring 首先检查一级缓存(singletonObjects)中是否已经存在所需的 bean 实例。如果存在,直接返回。

6. 检查二级缓存

如果一级缓存中没有找到,Spring 接着检查二级缓存(earlySingletonObjects)中是否有早期引用。如果存在,直接返回。

7. 检查三级缓存

如果二级缓存中也没有找到,Spring 会检查三级缓存(singletonFactories)是否有对应的 ObjectFactory。如果有,Spring 会通过 ObjectFactory 获取早期引用,并将其放入二级缓存,同时从三级缓存中移除。

ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
    Object earlySingletonReference = singletonFactory.getObject();
    // 将早期引用放入二级缓存
    earlySingletonObjects.put(beanName, earlySingletonReference);
    // 从三级缓存中移除
    singletonFactories.remove(beanName);
    return earlySingletonReference;
}

8. 完成属性填充和初始化

此时,原始 bean 和其依赖的 bean 都有了早期引用,可以继续进行属性填充和初始化。

9. 将完全初始化的 bean 放入一级缓存

当 bean 完成所有初始化步骤后,Spring 会将其从二级缓存中移除,并将其放入一级缓存,供后续使用。

addSingleton(beanName, singletonObject);

总结

通过上述流程,Spring 容器能够解决单例模式下 bean 的循环依赖问题。需要注意的是,这个机制依赖于以下条件:

  • bean 必须是单例模式。
  • bean 的创建过程不涉及 AOP,或者 AOP 的代理是通过三级缓存中的 ObjectFactory 生成的。 如果这些条件不满足,Spring 可能无法解决循环依赖问题。

iamarealgoodman avatar Aug 29 '24 03:08 iamarealgoodman