getBean源码实战(五)------MergedBean
代码仓库 :Gitee 仓库链接
本文档的所有示例代码都可以在代码仓库中找到,建议结合代码一起阅读。
1. MergedBeanDefinition 简介
1.1 什么是 MergedBeanDefinition
MergedBeanDefinition(合并后的 Bean 定义)是 Spring 在创建 Bean 实例之前,对原始 Bean 定义进行处理后得到的完整 Bean 定义。
核心概念:
- 原始 Bean 定义 :从 XML 配置或注解中解析得到的
BeanDefinition,可能包含parent属性,指向父 Bean 定义 - 合并后的 Bean 定义 :将子 Bean 定义和父 Bean 定义合并后得到的
RootBeanDefinition,包含了所有需要的信息
为什么需要合并?
在 Spring 中,Bean 定义支持继承机制。子 Bean 可以通过 parent 属性继承父 Bean 的配置,同时可以覆盖父 Bean 的属性值。例如:
xml
<!-- 父 Bean:抽象 Bean -->
<bean id="baseService" class="com.example.abstractbean.BaseService" abstract="true">
<property name="version" value="1.0.0"/>
<property name="enabled" value="true"/>
</bean>
<!-- 子 Bean:继承父 Bean -->
<bean id="userService" class="com.example.abstractbean.UserService" parent="baseService">
<property name="name" value="用户服务"/>
</bean>
在创建 userService 时,Spring 需要:
- 获取
userService的原始 Bean 定义 - 获取
baseService的 Bean 定义(父 Bean) - 将父 Bean 的属性合并到子 Bean 中
- 用子 Bean 的属性覆盖父 Bean 的属性
- 得到最终的、完整的 Bean 定义
这个合并后的 Bean 定义就是 MergedBeanDefinition。
1.2 MergedBeanDefinition 的使用场景
MergedBeanDefinition 主要在以下场景中使用:
- Bean 定义继承 :当子 Bean 通过
parent属性继承父 Bean 的配置时 - 抽象 Bean:抽象 Bean 不能直接实例化,但可以作为父 Bean 被继承
- 配置复用:多个 Bean 共享相同的配置时,可以定义抽象 Bean 作为模板
- 属性覆盖:子 Bean 可以覆盖父 Bean 的属性值,同时继承其他属性
关键方法:
getMergedLocalBeanDefinition(beanName):获取本地合并后的 Bean 定义getMergedBeanDefinition(beanName):获取合并后的 Bean 定义(可能从父 BeanFactory 获取)checkMergedBeanDefinition(mbd, beanName, args):检查合并后的 Bean 定义是否有效(如是否为抽象 Bean)
2. 示例 Bean:抽象 Bean 继承
2.1 Bean 类定义
BaseService:
1:15:spring-source/code/spring-basic/src/main/java/com/example/abstractbean/BaseService.java
package com.example.abstractbean;
/**
* 基础服务类,用于演示抽象 bean
*/
public class BaseService {
private String name;
private String version;
private boolean enabled;
public BaseService() {
System.out.println("BaseService 构造函数被调用");
}
// getter/setter 方法已省略,完整代码请查看源码链接
// toString 方法已省略,完整代码请查看源码链接
public void init() {
System.out.println("BaseService 初始化方法被调用");
}
}
UserService:
1:15:spring-source/code/spring-basic/src/main/java/com/example/abstractbean/UserService.java
package com.example.abstractbean;
/**
* 用户服务类,继承自 BaseService
*/
public class UserService extends BaseService {
private String databaseUrl;
public UserService() {
System.out.println("UserService 构造函数被调用");
}
// getter/setter 方法已省略,完整代码请查看源码链接
// toString 方法已省略,完整代码请查看源码链接
public void processUser() {
System.out.println("UserService 处理用户数据,数据库URL: " + databaseUrl);
}
}
OrderService:
1:15:spring-source/code/spring-basic/src/main/java/com/example/abstractbean/OrderService.java
package com.example.abstractbean;
/**
* 订单服务类,继承自 BaseService
*/
public class OrderService extends BaseService {
private String cacheUrl;
public OrderService() {
System.out.println("OrderService 构造函数被调用");
}
// getter/setter 方法已省略,完整代码请查看源码链接
// toString 方法已省略,完整代码请查看源码链接
public void processOrder() {
System.out.println("OrderService 处理订单数据,缓存URL: " + cacheUrl);
}
}
2.2 XML 配置
1:42:spring-source/code/spring-basic/src/main/resources/applicationContext-abstractbean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
抽象 Bean 配置示例
核心要点:
1. 使用 abstract="true" 定义抽象 bean,抽象 bean 不会被实例化
2. 使用 parent 属性让其他 bean 继承抽象 bean 的配置
3. 子 bean 可以覆盖父 bean 的属性值
4. 子 bean 可以添加自己的属性
5. 抽象 bean 通常用于定义公共的配置,避免重复配置
-->
<!-- 定义抽象 bean:基础服务配置 -->
<bean id="baseService" class="com.example.abstractbean.BaseService" abstract="true">
<property name="name" value="基础服务"/>
<property name="version" value="1.0.0"/>
<property name="enabled" value="true"/>
</bean>
<!-- 用户服务:继承抽象 bean baseService -->
<bean id="userService" class="com.example.abstractbean.UserService" parent="baseService">
<!-- 覆盖父 bean 的属性 -->
<property name="name" value="用户服务"/>
<!-- 添加自己的属性 -->
<property name="databaseUrl" value="jdbc:mysql://localhost:3306/user_db"/>
</bean>
<!-- 订单服务:继承抽象 bean baseService -->
<bean id="orderService" class="com.example.abstractbean.OrderService" parent="baseService">
<!-- 覆盖父 bean 的属性 -->
<property name="name" value="订单服务"/>
<!-- 添加自己的属性 -->
<property name="cacheUrl" value="redis://localhost:6379"/>
</bean>
</beans>
2.3 测试类
测试类位置:code/spring-basic/src/test/java/com/example/abstractbean/AbstractBeanTest.java
该测试类包含以下测试方法:
testAbstractBeanCannotBeInstantiated():测试抽象 bean 不能被实例化testChildBeanInheritsParentProperties():测试子 bean 继承抽象 bean 的配置testChildBeanOverridesParentProperties():测试子 bean 可以覆盖父 bean 的属性testMultipleChildBeansInheritSameAbstractBean():测试多个子 bean 可以继承同一个抽象 bean
3. 源码分析
3.1 getMergedLocalBeanDefinition 方法
getMergedLocalBeanDefinition 方法用于获取本地(当前 BeanFactory)的合并后的 Bean 定义。
方法作用:
- 从
mergedBeanDefinitions缓存中获取已合并的 Bean 定义 - 如果缓存中没有,则调用
getMergedBeanDefinition进行合并 - 将合并后的结果放入缓存,避免重复合并
关键点:
- 该方法只处理当前 BeanFactory 中的 Bean 定义
- 如果 Bean 定义有
parent属性,会递归合并父 Bean 定义 - 合并后的 Bean 定义会被缓存,提高后续获取的性能
执行流程:
java
// AbstractBeanFactory.java
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) {
// 1. 从缓存中获取已合并的 Bean 定义
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
// 2. 缓存中没有,获取原始 Bean 定义并合并
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
源码说明:
this.mergedBeanDefinitions是Map<String, RootBeanDefinition>类型的缓存getBeanDefinition(beanName)从beanDefinitionMap中获取原始 Bean 定义- 如果原始 Bean 定义有
parentName,会在getMergedBeanDefinition中递归处理
缓存机制:
mergedBeanDefinitions是一个Map<String, RootBeanDefinition>类型的缓存- 第一次获取某个 Bean 的合并定义时,会进行合并并放入缓存
- 后续获取同一个 Bean 的合并定义时,直接从缓存中返回,提高性能
- 当 Bean 定义被覆盖或重置时,会清理对应的缓存(通过
clearMergedBeanDefinition方法)
3.2 getMergedBeanDefinition 方法
getMergedBeanDefinition 是合并 Bean 定义的核心方法。本次的重点在 getMergedBeanDefinition 这个方法中的一个分支:处理有 parentBeanName 的 Bean 定义。
3.2.1 没有 parentBeanName 的情况(普通 Bean)
对于没有 parent 属性的普通 Bean(如我们在getBean源码实战(一)中分析的 UserService),处理流程相对简单:
- 从
beanDefinitionMap中获取原始 Bean 定义(GenericBeanDefinition) - 直接封装成
RootBeanDefinition - 设置默认值(如
scope默认为singleton) - 放入
mergedBeanDefinitions缓存 - 返回合并后的 Bean 定义
这种情况下,合并过程实际上只是将 GenericBeanDefinition 转换为 RootBeanDefinition,没有真正的"合并"操作。
3.2.2 处理 parentBeanName 的流程(重点)
getMergedBeanDefinition 方法的完整实现逻辑如下:
java
// AbstractBeanFactory.java
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
// 1. 从缓存中获取已合并的 Bean 定义
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
// 2. 检查是否有父 Bean 定义
if (bd.getParentName() != null) {
// 处理有 parentBeanName 的情况
if (!beanName.equals(bd.getParentName())) {
// 步骤 1:解析 parentBeanName
String parentBeanName = transformedBeanName(bd.getParentName());
// 步骤 2:递归获取父级 Bean 定义
if (parentBeanName != null && !parentBeanName.equals(beanName)) {
BeanDefinition pbd;
try {
// 尝试从当前 BeanFactory 获取
pbd = getMergedBeanDefinition(parentBeanName);
} catch (NoSuchBeanDefinitionException ex) {
// 如果当前 BeanFactory 中没有,尝试从父级 BeanFactory 获取
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parentBeanFactory)
.getMergedBeanDefinition(parentBeanName);
} else {
throw ex;
}
}
// 步骤 3:创建基于父 Bean 定义的 RootBeanDefinition
mbd = new RootBeanDefinition(pbd);
// 使用子 Bean 定义的属性覆盖父 Bean 定义的属性
mbd.overrideFrom(bd);
}
} else {
// parentBeanName 和 beanName 相同,说明配置错误
throw new BeanDefinitionStoreException(...);
}
} else {
// 没有 parentBeanName,直接封装为 RootBeanDefinition
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
} else {
mbd = new RootBeanDefinition(bd);
}
}
// 步骤 4:缓存合并结果
if (!bd.isSingleton()) {
// 非单例 Bean 不缓存(因为每次都需要创建新实例)
mbd.setTargetType(getResolvedType(beanName, mbd));
} else {
// 单例 Bean 放入缓存
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
关键步骤说明:
步骤 1:解析 parentBeanName
java
String parentBeanName = transformedBeanName(bd.getParentName());
- 通过
transformedBeanName方法进行解析(之前看过这个方法:去掉&,通过别名找到原始的bean) - 处理 FactoryBean 的前缀
&和别名解析
步骤 2:递归获取父级 Bean 定义
java
if (parentBeanName != null && !parentBeanName.equals(beanName)) {
BeanDefinition pbd = getMergedBeanDefinition(parentBeanName);
// ... 如果当前 BeanFactory 中没有,尝试从父级 BeanFactory 获取
}
- 如果 BeanName 和 parentBeanName 不同,则通过
getMergedBeanDefinition(parentBeanName)递归获取父级 Bean 定义 - 该方法里也会判断是否用父级 Bean 工厂加载(
getParentBeanFactory()) - 我们当前均没有尝试使用父级,这可以先看
getMergedLocalBeanDefinition(beanName)方法
步骤 3:合并 Bean 定义
java
// 创建新的 RootBeanDefinition,基于父 Bean 定义
RootBeanDefinition mbd = new RootBeanDefinition(pbd);
// 使用子 Bean 定义的属性覆盖父 Bean 定义的属性
mbd.overrideFrom(bd);
overrideFrom 方法详解:
overrideFrom 是 RootBeanDefinition 中的方法,用于用子 Bean 定义的属性覆盖父 Bean 定义的属性。其实现逻辑如下:
java
// RootBeanDefinition.java
public void overrideFrom(BeanDefinition other) {
if (other instanceof AbstractBeanDefinition) {
AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other;
// 1. 覆盖 Bean 类名和类
if (otherAbd.hasBeanClass()) {
setBeanClass(otherAbd.getBeanClass());
} else if (otherAbd.getBeanClassName() != null) {
setBeanClassName(otherAbd.getBeanClassName());
}
// 2. 覆盖作用域
if (otherAbd.hasPropertyValues()) {
setScope(otherAbd.getScope());
}
// 3. 覆盖工厂相关属性
if (otherAbd.getFactoryBeanName() != null) {
setFactoryBeanName(otherAbd.getFactoryBeanName());
}
if (otherAbd.getFactoryMethodName() != null) {
setFactoryMethodName(otherAbd.getFactoryMethodName());
}
// 4. 覆盖构造参数
if (otherAbd.hasConstructorArgumentValues()) {
getConstructorArgumentValues().addArgumentValues(
otherAbd.getConstructorArgumentValues());
}
// 5. 覆盖属性值(PropertyValues)
if (otherAbd.hasPropertyValues()) {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValues(getPropertyValues());
propertyValues.addPropertyValues(otherAbd.getPropertyValues());
setPropertyValues(propertyValues);
}
// 6. 覆盖方法覆盖(lookup-method 和 replaced-method)
if (otherAbd.hasMethodOverrides()) {
getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
}
// 7. 覆盖其他属性
setLazyInit(otherAbd.isLazyInit());
setAutowireMode(otherAbd.getAutowireMode());
setDependencyCheck(otherAbd.getDependencyCheck());
if (otherAbd.getDependsOn() != null) {
setDependsOn(otherAbd.getDependsOn());
}
setAutowireCandidate(otherAbd.isAutowireCandidate());
setPrimary(otherAbd.isPrimary());
setRole(otherAbd.getRole());
setDescription(otherAbd.getDescription());
setResourceDescription(otherAbd.getResourceDescription());
setSource(otherAbd.getSource());
// 8. 覆盖元数据属性
copyAttributesFrom(otherAbd);
}
}
覆盖的属性列表:
setBeanClassName:Bean 类名setBeanClass:Bean 类setScope:作用域setFactoryBeanName:工厂 Bean 名称setFactoryMethodName:工厂方法名称- 构造参数:构造函数参数值(通过
addArgumentValues添加) - properties 值:属性值(通过
addPropertyValues添加,子 Bean 的属性会覆盖父 Bean 的同名属性) - 覆盖方法:lookup-method 和 replaced-method(通过
addOverrides添加) setLazyInit:懒加载setAutowireMode:自动装配模式setDependencyCheck:依赖检查setDependsOn:依赖的 BeansetAutowireCandidate:是否作为自动装配候选setPrimary:是否为主要 BeansetRole:Bean 的角色setDescription:描述信息setResourceDescription:资源描述setSource:源对象- 元数据属性:通过
copyAttributesFrom复制
步骤 4:缓存合并结果
java
// 单例 Bean 放入缓存
if (bd.isSingleton()) {
this.mergedBeanDefinitions.put(beanName, mbd);
} else {
// 非单例 Bean 不缓存(因为每次都需要创建新实例)
mbd.setTargetType(getResolvedType(beanName, mbd));
}
- 将 beanName 与合并后的 bean 定义放入
mergedBeanDefinitions缓存中 - 注意:只有单例 Bean 才会被缓存,非单例 Bean(prototype)每次获取时都会重新合并
- 避免重复合并,提高性能
步骤 5:复制相关缓存
java
// AbstractBeanFactory.java
protected void copyRelevantMergedBeanDefinitionCaches(
RootBeanDefinition source, RootBeanDefinition target) {
// 复制方法覆盖缓存
if (source.hasMethodOverrides()) {
target.copyMethodOverridesFrom(source);
}
// 复制其他相关缓存信息
// ...
}
- 这个方法的作用暂时保留,个人理解是需要重新覆盖 bean 时才会走进来
- 主要用于处理 Bean 定义覆盖的场景
- 将父 Bean 定义中的一些缓存信息(如方法覆盖缓存)复制到子 Bean 定义中
- 确保子 Bean 定义能够正确继承父 Bean 定义的方法覆盖信息
完整流程对比:
| 场景 | 处理方式 | 结果 |
|---|---|---|
| 没有 parentBeanName | 直接封装为 RootBeanDefinition | 原始 Bean 定义的完整副本 |
| 有 parentBeanName | 递归合并父 Bean 定义,然后覆盖 | 父 Bean + 子 Bean 的合并结果 |
3.2.3 为什么需要合并而不是直接使用原始 Bean 定义?
💡 思考问题:其实在 bean 定义读取时也有一个 userService 的 bean 定义,那这里为什么不直接使用?
原因分析:
-
原始 Bean 定义不完整:
- 原始 Bean 定义(
GenericBeanDefinition)只包含子 Bean 自己的配置 - 例如
userService的原始定义中只有name="用户服务"和databaseUrl - 缺少从父 Bean
baseService继承的属性(version、enabled)
- 原始 Bean 定义(
-
需要合并父 Bean 的属性:
- 父 Bean
baseService定义了version="1.0.0"和enabled="true" - 这些属性需要合并到子 Bean 中,才能得到完整的 Bean 定义
- 父 Bean
-
支持属性覆盖:
- 子 Bean 可以覆盖父 Bean 的属性(如
name属性) - 合并过程会正确处理覆盖逻辑
- 子 Bean 可以覆盖父 Bean 的属性(如
-
统一 Bean 定义类型:
- 合并后的 Bean 定义统一为
RootBeanDefinition类型 - 便于后续的 Bean 创建流程使用
- 合并后的 Bean 定义统一为
示例说明:
xml
<!-- 父 Bean -->
<bean id="baseService" abstract="true">
<property name="version" value="1.0.0"/>
<property name="enabled" value="true"/>
<property name="name" value="基础服务"/>
</bean>
<!-- 子 Bean -->
<bean id="userService" parent="baseService">
<property name="name" value="用户服务"/> <!-- 覆盖父 Bean 的 name -->
<property name="databaseUrl" value="jdbc:mysql://..."/>
</bean>
原始 Bean 定义 (userService):
name = "用户服务"databaseUrl = "jdbc:mysql://..."- ❌ 缺少
version和enabled
合并后的 Bean 定义 (userService):
name = "用户服务"(子 Bean 覆盖)version = "1.0.0"(从父 Bean 继承)enabled = true(从父 Bean 继承)databaseUrl = "jdbc:mysql://..."(子 Bean 自己的属性)- ✅ 包含所有需要的属性
3.3 checkMergedBeanDefinition 方法
得到了融合后的 bean 定义后,会通过 this.checkMergedBeanDefinition(mbd, beanName, args) 方法检查 bean 定义是否有效。
方法作用:
- 检查合并后的 Bean 定义是否为抽象 Bean
- 抽象 Bean 不能实例化,如果尝试获取抽象 Bean,会抛出
BeanIsAbstractException异常
检查逻辑:
java
// AbstractBeanFactory.java
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
throws BeanDefinitionStoreException {
// 检查是否为抽象 Bean
if (mbd.isAbstract()) {
throw new BeanIsAbstractException(beanName);
}
}
源码位置 :AbstractBeanFactory.checkMergedBeanDefinition()
调用时机 :在 doGetBean 方法中,获取合并后的 Bean 定义后立即调用:
java
// AbstractBeanFactory.java - doGetBean 方法片段
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType,
@Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
// ... 前面的步骤(翻译 beanName、获取单例等)
// 获取合并后的 Bean 定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查 Bean 定义是否有效(是否为抽象 Bean)
checkMergedBeanDefinition(mbd, beanName, args);
// ... 后续的 Bean 创建流程
}
为什么需要这个检查?
- 抽象 Bean 的定义:抽象 Bean 通常作为模板,用于被其他 Bean 继承
- 防止误用:如果直接尝试获取抽象 Bean,说明配置或使用有误
- 提前发现错误:在 Bean 创建之前就发现配置问题,避免浪费资源
示例:
java
// 尝试获取抽象 Bean baseService,会抛出异常
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("applicationContext-abstractbean.xml")
);
// 这会抛出 BeanIsAbstractException
factory.getBean("baseService", BaseService.class);
正确的使用方式:
java
// 获取继承抽象 Bean 的子 Bean,这是正确的
UserService userService = factory.getBean("userService", UserService.class);
// userService 包含了从 baseService 继承的所有属性
3.4 后续流程
其实到这里后续的逻辑都基本一致了,因为这 UserService 的 bean 定义都完全了,剩下的就是实例化后,进行的赋值和依赖赋值的步骤了。
4. 调试过程
4.1 调试 userService Bean 的合并过程
以 userService Bean 为例,调试其 Bean 定义的合并过程:
步骤 1:获取 userService 的原始 Bean 定义
在 doGetBean 方法中,调用 getMergedLocalBeanDefinition("userService"):
- 从
beanDefinitionMap中获取userService的原始 Bean 定义(GenericBeanDefinition) - 发现该 Bean 定义有
parentName = "baseService"
步骤 2:合并父 Bean 定义
调用 getMergedBeanDefinition("userService"):
- 检测到
parentBeanName = "baseService" - 通过
transformedBeanName解析parentBeanName(本例中无需处理) - 递归调用
getMergedBeanDefinition("baseService")获取父 Bean 定义 - 父 Bean
baseService没有父 Bean,直接返回其RootBeanDefinition
步骤 3:创建合并后的 Bean 定义
- 创建新的
RootBeanDefinition,基于父 BeanbaseService的定义 - 调用
overrideFrom(userService的原始定义)进行属性覆盖 - 最终得到包含所有属性的完整 Bean 定义
步骤 4:检查 Bean 定义
调用 checkMergedBeanDefinition:
- 检查合并后的 Bean 定义是否为抽象
userService不是抽象 Bean,检查通过
步骤 5:后续流程
- Bean 定义合并完成,后续进入正常的 Bean 创建流程
- 实例化、属性赋值、依赖注入等步骤与普通 Bean 一致
4.2 调试抽象 Bean 的检查
尝试获取抽象 Bean baseService:
java
factory.getBean("baseService", BaseService.class);
执行流程:
- 调用
getMergedBeanDefinition("baseService") - 合并 Bean 定义(
baseService没有父 Bean,直接返回) - 调用
checkMergedBeanDefinition - 检测到
baseService是抽象 Bean(abstract="true") - 抛出
BeanIsAbstractException异常
5. 总结
5.1 MergedBeanDefinition 的核心作用
- Bean 定义继承 :支持子 Bean 通过
parent属性继承父 Bean 的配置 - 属性合并:将父 Bean 和子 Bean 的属性合并,得到完整的 Bean 定义
- 属性覆盖:子 Bean 可以覆盖父 Bean 的属性值
- 配置复用:通过抽象 Bean 实现配置的复用,提高可维护性
5.2 关键方法总结
| 方法 | 作用 | 说明 |
|---|---|---|
getMergedLocalBeanDefinition |
获取本地合并后的 Bean 定义 | 从缓存获取或调用 getMergedBeanDefinition |
getMergedBeanDefinition |
合并 Bean 定义 | 处理 parentBeanName,递归合并父 Bean 定义 |
overrideFrom |
覆盖属性 | 用子 Bean 定义的属性覆盖父 Bean 定义的属性 |
checkMergedBeanDefinition |
检查 Bean 定义 | 检查是否为抽象 Bean,防止实例化抽象 Bean |
5.3 合并流程总结
原始 Bean 定义(GenericBeanDefinition)
↓
检测 parentBeanName
↓
递归获取父 Bean 定义
↓
创建 RootBeanDefinition(基于父 Bean)
↓
调用 overrideFrom(用子 Bean 属性覆盖)
↓
合并后的 Bean 定义(RootBeanDefinition)
↓
检查是否为抽象 Bean
↓
后续 Bean 创建流程
5.4 与之前文章的联系
- Bean 定义加载 :在 XML 解析时,
parent属性被解析为parentName存储在GenericBeanDefinition中 - Bean 定义注册 :原始 Bean 定义被注册到
beanDefinitionMap中 - Bean 创建 :在
doGetBean方法中,通过getMergedLocalBeanDefinition获取合并后的 Bean 定义 - 后续流程:合并后的 Bean 定义用于 Bean 的实例化、属性赋值和依赖注入
5.5 学习要点
- 理解 Bean 定义继承机制:Spring 通过合并机制实现 Bean 定义的继承
- 掌握合并流程 :理解
getMergedBeanDefinition的递归合并逻辑 - 理解属性覆盖:子 Bean 的属性会覆盖父 Bean 的同名属性
- 理解抽象 Bean:抽象 Bean 不能实例化,只能作为父 Bean 被继承
- 理解缓存机制:合并后的 Bean 定义会被缓存,避免重复合并
通过本文的分析,我们深入理解了 Spring 如何处理 Bean 定义的继承和合并,这是 Spring IoC 容器中一个重要的机制,为配置复用和代码简化提供了强大的支持。