【Spring源码】通过 Bean 工厂获取 Bean 的过程

通过 Bean 工厂获取 Bean 的过程

代码仓库Gitee 仓库链接

本文档的所有示例代码都可以在代码仓库中找到,建议结合代码一起阅读。

学习思路说明

getBean() 方法的源码逻辑相比之前的 Bean 定义加载过程更加复杂,涉及单例缓存、循环依赖处理、FactoryBean 处理、Bean 生命周期管理等多个环节。为了让大家更好地理解整个流程,本文采用以下学习策略:

  1. 整体流程先行 :首先从宏观角度总结 Bean 获取的完整流程,帮助大家建立对 getBean() 方法执行链路的基本认知。
  2. 分场景深入:在有了整体印象之后,我们将按照不同的 Bean 配置场景(如单例 Bean、Prototype Bean、FactoryBean、循环依赖等)进行深入的源码阅读和分析。
  3. 实践验证:对于源码中尚未覆盖到的代码路径,我们会通过配置相应的 Bean 定义和编写测试用例来进行实际调试,确保对每个关键路径都有深入的理解。

通过这种"先整体后局部,先理论后实践"的学习方式,我们可以更系统、更全面地掌握 Spring Bean 获取机制的设计思想和实现细节。


回顾学习历程

在之前的文章中,我们深入探索了 Spring 从 XML 配置文件加载 Bean 定义的全过程。从 XML 配置的校验、解析到 Bean 定义的注册,我们逐步了解了 Spring 框架在 Bean 定义加载阶段的设计思想和实现细节。

现在,Bean 定义已经注册到容器中,接下来我们需要了解:当调用 getBean() 方法时,Spring 是如何根据 Bean 定义创建 Bean 实例的?

本文将深入探索通过 Bean 工厂获取 Bean 的完整过程,包括:

  1. Bean 获取的整体流程
  2. 单例 Bean 的获取机制
  3. Prototype Bean 的获取机制
  4. FactoryBean 的处理
  5. 循环依赖的解决
  6. Bean 的创建过程

Bean 获取的整体流程

入口方法:getBean()

BeanFactory 接口定义了多个 getBean() 方法的重载版本:

java 复制代码
// 根据名称获取 Bean
Object getBean(String name) throws BeansException;

// 根据名称和类型获取 Bean
<T> T getBean(String name, Class<T> requiredType) throws BeansException;

// 根据类型获取 Bean
<T> T getBean(Class<T> requiredType) throws BeansException;

// 根据名称和参数获取 Bean(用于构造函数注入)
Object getBean(String name, Object... args) throws BeansException;

核心实现:AbstractBeanFactory.getBean()

AbstractBeanFactoryBeanFactory 接口的抽象实现,提供了 getBean() 方法的核心逻辑:

java 复制代码
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
}

关键发现 :所有的 getBean() 方法最终都调用了 doGetBean() 方法,这是 Bean 获取的核心方法。


doGetBean() 方法的核心流程

doGetBean() 方法是 Bean 获取的核心方法,它包含了 Bean 获取的完整逻辑。让我们逐步分析这个方法:

第一步:转换 Bean 名称

java 复制代码
final String beanName = transformedBeanName(name);

作用

  • 处理 FactoryBean 的特殊前缀 &
  • 处理别名,将别名转换为实际的 Bean 名称

示例

  • "&myFactoryBean""myFactoryBean"(获取 FactoryBean 本身)
  • "myBean""realBean"(如果 myBean 是别名,则转换为实际名称)

第二步:尝试从缓存获取单例 Bean

java 复制代码
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

作用

  • 从单例缓存中获取已存在的 Bean 实例
  • 如果找到,直接返回(单例 Bean 只创建一次)
  • 如果未找到,继续后续的创建流程

缓存结构

  • singletonObjects:存储完全初始化好的单例 Bean
  • earlySingletonObjects:存储提前暴露的单例 Bean(用于解决循环依赖)
  • singletonFactories:存储单例 Bean 的工厂对象

第三步:检查 Bean 定义是否存在

java 复制代码
BeanDefinition bd = getMergedBeanDefinition(beanName);

作用

  • 获取合并后的 Bean 定义(包括父 Bean 定义的属性)
  • 如果 Bean 定义不存在,抛出 NoSuchBeanDefinitionException

第四步:检查依赖的 Bean

java 复制代码
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException(...); // 循环依赖检查
        }
        registerDependentBean(dep, beanName);
        getBean(dep); // 递归获取依赖的 Bean
    }
}

作用

  • 检查 Bean 的 depends-on 属性
  • 如果存在依赖,先递归获取依赖的 Bean
  • 检查是否存在循环依赖

第五步:根据作用域创建 Bean

java 复制代码
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        return createBean(beanName, mbd, args);
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
    // 其他作用域(request、session 等)
    String scopeName = mbd.getScope();
    Scope scope = this.scopes.get(scopeName);
    Object scopedInstance = scope.get(beanName, () -> {
        return createBean(beanName, mbd, args);
    });
    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}

关键点

  • 单例 Bean :通过 getSingleton() 方法创建,确保只创建一次
  • Prototype Bean:每次调用都创建新实例
  • 其他作用域 :通过 Scope 接口管理

单例 Bean 的获取机制

getSingleton() 方法的三级缓存机制

DefaultSingletonBeanRegistry.getSingleton() 方法实现了单例 Bean 的三级缓存机制:

java 复制代码
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 第一级缓存:完全初始化好的单例 Bean
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 第二级缓存:提前暴露的单例 Bean(用于解决循环依赖)
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 第三级缓存:单例 Bean 的工厂对象
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

三级缓存的作用

  1. singletonObjects(一级缓存)

    • 存储完全初始化好的单例 Bean
    • 这是最终返回给用户的 Bean 实例
  2. earlySingletonObjects(二级缓存)

    • 存储提前暴露的单例 Bean
    • 用于解决循环依赖问题
    • 这些 Bean 可能还没有完全初始化
  3. singletonFactories(三级缓存)

    • 存储单例 Bean 的工厂对象
    • 用于创建提前暴露的 Bean 实例
    • 创建后会被移到二级缓存

循环依赖的解决机制

问题场景

  • BeanA 依赖 BeanB
  • BeanB 依赖 BeanA

解决流程

  1. 创建 BeanA

    • 调用构造函数创建 BeanA 实例(此时 BeanA 还未完全初始化)
    • 将 BeanA 的工厂对象放入三级缓存
    • 开始注入 BeanA 的属性
  2. 注入 BeanB

    • 发现 BeanA 需要注入 BeanB
    • 调用 getBean("beanB") 获取 BeanB
  3. 创建 BeanB

    • 调用构造函数创建 BeanB 实例
    • 将 BeanB 的工厂对象放入三级缓存
    • 开始注入 BeanB 的属性
  4. 注入 BeanA

    • 发现 BeanB 需要注入 BeanA
    • 调用 getBean("beanA")
    • 从三级缓存中获取 BeanA 的工厂对象
    • 创建 BeanA 的提前暴露实例,放入二级缓存
    • 返回给 BeanB 使用
  5. 完成 BeanB 的初始化

    • BeanB 完成属性注入
    • BeanB 从三级缓存移到一级缓存
  6. 完成 BeanA 的初始化

    • BeanA 完成属性注入
    • BeanA 从二级缓存移到一级缓存

关键点

  • 三级缓存机制允许在 Bean 完全初始化之前暴露 Bean 实例
  • 只适用于单例 Bean,Prototype Bean 无法使用此机制
  • 只适用于通过 setter 注入的循环依赖,构造函数注入的循环依赖无法解决

Prototype Bean 的获取机制

Prototype Bean 的获取相对简单,因为每次都需要创建新实例:

java 复制代码
else if (mbd.isPrototype()) {
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

关键点

  • 每次调用 getBean() 都会创建新实例
  • 不放入任何缓存
  • 如果存在循环依赖,会抛出异常(因为无法提前暴露实例)

FactoryBean 的处理

getObjectForBeanInstance() 方法

在获取 Bean 实例后,需要检查是否是 FactoryBean:

java 复制代码
protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
    // 如果名称以 & 开头,直接返回 FactoryBean 本身
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName);
        }
        return beanInstance;
    }
    
    // 如果不是 FactoryBean,直接返回
    if (!(beanInstance instanceof FactoryBean)) {
        return beanInstance;
    }
    
    // 如果是 FactoryBean,获取它创建的对象
    Object object = null;
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

关键逻辑

  1. 如果名称以 & 开头,返回 FactoryBean 本身
  2. 如果不是 FactoryBean,直接返回实例
  3. 如果是 FactoryBean,调用 getObjectFromFactoryBean() 获取目标对象

getObjectFromFactoryBean() 方法

java 复制代码
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(factory, beanName);
                if (shouldPostProcess) {
                    try {
                        object = postProcessObjectFromFactoryBean(object, beanName);
                    }
                    catch (Throwable ex) {
                        throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                    }
                }
                this.factoryBeanObjectCache.put(beanName, object);
            }
            return object;
        }
    }
    else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

关键逻辑

  • 如果 FactoryBean 是单例,将创建的对象缓存到 factoryBeanObjectCache
  • 如果 FactoryBean 是 Prototype,每次调用都创建新对象
  • 调用 factory.getObject() 创建目标对象
  • 应用后置处理器(如果需要)

Bean 的创建过程:createBean()

createBean() 方法是 Bean 创建的核心方法,它负责根据 Bean 定义创建 Bean 实例:

java 复制代码
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 解析 Bean 的类
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    
    // 2. 准备方法覆盖(lookup-method、replaced-method)
    mbd.prepareMethodOverrides();
    
    // 3. 应用 BeanPostProcessor(实例化前)
    Object bean = resolveBeforeInstantiation(beanName, mbd);
    if (bean != null) {
        return bean;
    }
    
    // 4. 创建 Bean 实例
    Object beanInstance = doCreateBean(beanName, mbd, args);
    
    return beanInstance;
}

doCreateBean() 方法

doCreateBean() 方法执行实际的 Bean 创建逻辑:

java 复制代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 实例化 Bean(调用构造函数)
    BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
    Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    
    // 2. 应用 MergedBeanDefinitionPostProcessor
    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    
    // 3. 提前暴露 Bean(用于解决循环依赖)
    boolean earlySingletonExposure = (mbd.isSingleton() && 
            this.allowCircularReferences && 
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    
    // 4. 初始化 Bean(属性注入、初始化方法等)
    Object exposedObject = bean;
    try {
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        // 异常处理
    }
    
    // 5. 注册单例 Bean
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
        }
    }
    
    return exposedObject;
}

关键步骤

  1. createBeanInstance():创建 Bean 实例

    • 选择合适的构造函数
    • 调用构造函数创建实例
    • 返回 BeanWrapper 对象
  2. populateBean():填充 Bean 属性

    • 解析属性值
    • 注入依赖的 Bean
    • 应用属性后置处理器
  3. initializeBean():初始化 Bean

    • 调用 BeanPostProcessor.postProcessBeforeInitialization()
    • 调用初始化方法(init-methodInitializingBean.afterPropertiesSet()
    • 调用 BeanPostProcessor.postProcessAfterInitialization()

代码示例

示例 1:单例 Bean 的获取

配置文件applicationContext-getbean.xml

xml 复制代码
<bean id="userService" class="com.example.getbean.UserService">
    <property name="name" value="用户服务"/>
</bean>

测试代码

java 复制代码
@Test
public void testGetSingletonBean() {
    BeanFactory factory = new XmlBeanFactory(
        new ClassPathResource("applicationContext-getbean.xml")
    );
    
    // 第一次获取
    UserService service1 = factory.getBean("userService", UserService.class);
    
    // 第二次获取
    UserService service2 = factory.getBean("userService", UserService.class);
    
    // 验证是同一个实例
    assertSame(service1, service2);
}

示例 2:Prototype Bean 的获取

配置文件

xml 复制代码
<bean id="prototypeBean" class="com.example.getbean.PrototypeBean" scope="prototype">
    <property name="name" value="原型Bean"/>
</bean>

测试代码

java 复制代码
@Test
public void testGetPrototypeBean() {
    BeanFactory factory = new XmlBeanFactory(
        new ClassPathResource("applicationContext-getbean.xml")
    );
    
    // 第一次获取
    PrototypeBean bean1 = factory.getBean("prototypeBean", PrototypeBean.class);
    
    // 第二次获取
    PrototypeBean bean2 = factory.getBean("prototypeBean", PrototypeBean.class);
    
    // 验证是不同的实例
    assertNotSame(bean1, bean2);
}

示例 3:循环依赖的解决

配置文件

xml 复制代码
<bean id="serviceA" class="com.example.getbean.ServiceA">
    <property name="serviceB" ref="serviceB"/>
</bean>

<bean id="serviceB" class="com.example.getbean.ServiceB">
    <property name="serviceA" ref="serviceA"/>
</bean>

测试代码

java 复制代码
@Test
public void testCircularDependency() {
    BeanFactory factory = new XmlBeanFactory(
        new ClassPathResource("applicationContext-getbean.xml")
    );
    
    // 获取 ServiceA,会触发循环依赖的解决
    ServiceA serviceA = factory.getBean("serviceA", ServiceA.class);
    ServiceB serviceB = factory.getBean("serviceB", ServiceB.class);
    
    // 验证循环依赖已解决
    assertNotNull(serviceA.getServiceB());
    assertNotNull(serviceB.getServiceA());
    assertSame(serviceA, serviceB.getServiceA());
    assertSame(serviceB, serviceA.getServiceB());
}

总结

通过本文的学习,我们深入了解了 Spring 通过 Bean 工厂获取 Bean 的完整过程:

核心流程

  1. Bean 名称转换:处理别名和 FactoryBean 前缀
  2. 缓存查找:从单例缓存中查找已存在的 Bean
  3. Bean 定义获取:获取合并后的 Bean 定义
  4. 依赖处理:递归获取依赖的 Bean
  5. Bean 创建:根据作用域创建 Bean 实例
  6. FactoryBean 处理:处理 FactoryBean 的特殊逻辑

关键机制

  1. 三级缓存机制

    • 一级缓存:完全初始化好的单例 Bean
    • 二级缓存:提前暴露的单例 Bean
    • 三级缓存:单例 Bean 的工厂对象
  2. 循环依赖解决

    • 只适用于单例 Bean
    • 只适用于 setter 注入
    • 通过提前暴露 Bean 实例解决
  3. FactoryBean 处理

    • 通过 & 前缀获取 FactoryBean 本身
    • 通过普通名称获取 FactoryBean 创建的对象
    • FactoryBean 创建的对象也会被缓存(如果是单例)

学习心得

通过阅读 Spring 源码,我们不仅了解了 Bean 获取的实现细节,更重要的是理解了 Spring 框架的设计思想:

  • 延迟加载:Bean 只有在需要时才创建
  • 缓存机制:通过多级缓存提高性能
  • 循环依赖解决:通过提前暴露实例解决循环依赖
  • 扩展性 :通过 BeanPostProcessor 等机制支持扩展

这些设计思想不仅适用于 Spring 框架,也可以应用到我们自己的项目中。


参考资料

代码仓库

  • Gitee 仓库查看完整代码
    • 配置文件:code/spring-basic/src/main/resources/applicationContext-getbean.xml
    • 测试代码:code/spring-basic/src/test/java/com/example/getbean/GetBeanProcessTest.java

Spring Framework 源码

  • BeanFactory 接口
  • AbstractBeanFactory 抽象类
  • DefaultListableBeanFactory 实现类
  • DefaultSingletonBeanRegistry 单例注册表

相关文档

相关推荐
Fortunate Chen2 小时前
类与对象(下)
java·javascript·jvm
程序员水自流2 小时前
【AI大模型第9集】Function Calling,让AI大模型连接外部世界
java·人工智能·llm
‿hhh2 小时前
综合交通运行协调与应急指挥平台项目说明
java·ajax·npm·json·需求分析·个人开发·规格说明书
小徐Chao努力2 小时前
【Langchain4j-Java AI开发】06-工具与函数调用
java·人工智能·python
无心水2 小时前
【神经风格迁移:全链路压测】33、全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器
java·python·性能优化
萧曵 丶2 小时前
Synchronized 详解及 JDK 版本优化
java·多线程·synchronized
夏幻灵2 小时前
JAVA基础:基本数据类型和引用数据类型
java·开发语言
weixin199701080162 小时前
闲鱼 item_get - 商品详情接口对接全攻略:从入门到精通
java·后端·spring
cike_y3 小时前
Spring-Bean的作用域&Bean的自动装配
java·开发语言·数据库·spring