Bean 的创建和管理

简介: Bean 的创建和管理

在 Spring 框架中,Bean 的创建和管理是其核心功能之一。为了优化 Bean 的创建过程并解决循环依赖等问题,Spring 引入了三级缓存机制。让我们深入探讨这一机制的工作原理和实现细节。

 

1. 什么是三级缓存?

 

Spring 的三级缓存主要用于解决单例 Bean 创建时的循环依赖问题。三级缓存分别是:

 

1. **一级缓存(singletonObjects)**:已经完全初始化好的单例 Bean。

2. **二级缓存(earlySingletonObjects)**:提前暴露的单例对象,尚未完全初始化,但已经实例化。

3. **三级缓存(singletonFactories)**:单例工厂,用于创建 Bean 对象的工厂。

 

2. 三级缓存的具体实现

 

三级缓存的实现主要在 `DefaultSingletonBeanRegistry` 类中进行。以下是该类中的相关属性:

 

```java
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // 一级缓存:存放完全初始化好的单例 Bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 
    // 二级缓存:提早曝光的单例对象,存放原始的 Bean 实例
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
 
    // 三级缓存:存放单例工厂对象,Bean工厂
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}
```

 

3. 三级缓存的工作流程

 

3.1 Bean 创建前的准备

 

当 Spring 需要创建一个 Bean 时,会先检查三级缓存,看看是否可以复用现有的 Bean 实例。

 

3.2 从缓存中获取 Bean

 

以下是从缓存中获取 Bean 的代码片段:

 

```java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从一级缓存中获取
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 如果一级缓存中没有,则从二级缓存中获取
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 如果二级缓存中也没有,则从三级缓存中获取,并放入二级缓存中
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
```

 

3.3 将 Bean 放入缓存

 

当 Bean 被创建出来后,会逐步将其放入各级缓存中,最终放入一级缓存中以表示它已经完全初始化好。

 

```java
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.earlySingletonObjects.remove(beanName);
        this.singletonFactories.remove(beanName);
    }
}
```

 

3.4 处理循环依赖

 

当一个 Bean 在创建过程中依赖另一个尚未完全初始化的 Bean 时,Spring 可以通过三级缓存机制提前暴露 Bean 的引用,从而解决循环依赖问题。

 

例如,当 Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A 时,创建过程如下:

 

1. 创建 Bean A,发现需要依赖 Bean B。

2. 检查缓存,发现 Bean B 尚未初始化,于是去创建 Bean B。

3. 创建 Bean B,发现依赖 Bean A。

4. 检查缓存,发现 Bean A 正在创建过程中,但还没有完全初始化。

5. 将 Bean A 的引用提前暴露,通过三级缓存机制,使得 Bean B 可以访问 Bean A。

6. Bean B 创建完成并放入缓存。

7. 返回继续创建 Bean A,使用已经创建好的 Bean B 完成 Bean A 的初始化。

8. 将完全初始化好的 Bean A 放入一级缓存。

 

4. 总结

 

Spring 的三级缓存机制是为了解决单例 Bean 创建过程中的循环依赖问题而设计的。通过引入三级缓存,Spring 可以提前暴露 Bean 的引用,使得其他 Bean 可以在创建过程中使用这些引用,从而有效地解决了循环依赖问题。

 

三级缓存机制的精妙之处在于它分阶段缓存 Bean 实例,从而确保在任何时刻都能找到合适的 Bean 引用,这不仅提高了 Bean 创建的效率,也增强了 Spring 容器的灵活性和健壮性。理解三级缓存机制对于深入掌握 Spring 框架的运行原理和优化应用程序的性能具有重要意义。

目录
相关文章
|
NoSQL MongoDB 存储
MongoDB 一致性模型设计与实现
本文源自阅读了 MongoDB 于 VLDB 19 上发表的 [Tunable Consistency in MongoDB](http://www.vldb.org/pvldb/vol12/p2071-schultz.pdf) 论文之后,在内部所做的分享(分享 PPT 见文末)。现在把分享的内容整理成此文,并且补充了部分在之前的分享中略过的细节,以及在分享中没有提及的 MongoDB Causa
2091 0
MongoDB 一致性模型设计与实现
|
22天前
|
Cloud Native Java API
Spring Boot 3.0 vs. 2.0
Spring Boot 3.0 带来革命性升级:全面支持 Java 17+ 与 Jakarta EE,引入原生编译、增强可观测性,推动云原生转型。相比 2.0,性能更强、启动更快、更现代。新项目应首选 3.0,老项目需逐步迁移,拥抱未来。
|
存储 安全 API
权限设计种类【RBAC、ABAC】
权限设计种类【RBAC、ABAC】
1985 2
|
关系型数据库 MySQL
用dbeaver创建一个enum类型,并讲述一部分,mysql的enum类型的知识
这篇文章介绍了如何在DBeaver中创建MySQL表的枚举(ENUM)字段,并探讨了MySQL中ENUM类型的一些行为特点,例如ENUM值的默认排序和在插入重复值时的表现。
344 1
用dbeaver创建一个enum类型,并讲述一部分,mysql的enum类型的知识
|
12月前
|
存储 监控 自动驾驶
对象存储OSS产品介绍
本次分享由王太平(征越)主讲,围绕阿里云对象存储OSS的产品介绍、成本优化、功能实战及最佳实践展开。内容涵盖OSS的五种存储类型及其应用场景,详细解析了生命周期管理在数据存储成本优化中的重要作用,并提供了具体的配置建议和实际案例。适合希望深入了解OSS及优化存储成本的用户参考。
607 0
|
druid Java 数据库连接
java报错Error attempting to get column ‘XXX’ from result set. Cause: java.sql.怎么解决?
java报错Error attempting to get column ‘XXX’ from result set. Cause: java.sql.怎么解决?
2965 0
java报错Error attempting to get column ‘XXX’ from result set. Cause: java.sql.怎么解决?
|
缓存 Java
Java基础12-深入理解Java中回调机制(一)
Java基础12-深入理解Java中回调机制(一)
195 5
|
Java Maven
Maven运行builder出现Failed to execute goal on projectXXXXX错误
Maven运行builder出现Failed to execute goal on projectXXXXX错误
364 7
|
弹性计算 JavaScript Ubuntu
ECS 挂载 OSS 多Bucket
ECS 挂载 OSS 多Bucket
253 0
Idea 进行远程服务器debug操作
Idea 进行远程服务器debug操作
1216 0