spring-beans 解析

Spring 框架中的 spring-beans 模块是 Spring IoC(控制反转)容器的核心组成部分,负责 Bean 的解析、定义、创建和管理。下面从解析的角度详细说明。

一、核心概念

1. Bean 定义解析的主要角色

  • BeanDefinition:Bean 的元数据描述(类名、作用域、生命周期、属性依赖等)

  • BeanDefinitionReader:读取配置(XML、注解、Java Config)并注册 BeanDefinition

  • BeanDefinitionRegistry:BeanDefinition 的注册中心(通常是 DefaultListableBeanFactory)

  • BeanFactoryPostProcessor:允许在 Bean 实例化前修改 BeanDefinition

二、XML 配置解析流程

典型配置

XML 复制代码
<beans xmlns="http://www.springframework.org/schema/beans">
    <bean id="userService" class="com.example.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>

解析步骤

  1. 资源加载ResourceLoader 加载 XML 资源

  2. 文档解析XmlBeanDefinitionReader 使用 DOM/SAX 解析 XML

  3. Bean 注册 :解析 <bean> 元素生成 GenericBeanDefinition,注册到 BeanDefinitionRegistry

关键代码位置

java 复制代码
// XmlBeanDefinitionReader 核心方法
public int loadBeanDefinitions(Resource resource) {
    // 1. 获取 XML 的 Document 对象
    Document doc = this.documentLoader.loadDocument(...);
    // 2. 注册 Bean 定义
    return registerBeanDefinitions(doc, resource);
}

// DefaultBeanDefinitionDocumentReader
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 遍历 <beans> 下的子元素
    if (delegate.isDefaultNamespace(root)) {
        for (Element ele : root.getChildNodes()) {
            if (ele.getNodeName().equals("bean")) {
                processBeanDefinition(ele, delegate);
            }
        }
    }
}

三、注解配置解析流程

常用注解

  • @Component, @Service, @Repository, @Controller

  • @Autowired, @Value, @Qualifier

解析方式

java 复制代码
// 方式1:使用 AnnotationConfigApplicationContext
new AnnotationConfigApplicationContext(AppConfig.class);

// 方式2:组件扫描
@ComponentScan(basePackages = "com.example")
public class AppConfig { }

// 解析核心类
// ClassPathBeanDefinitionScanner
// AnnotatedBeanDefinitionReader

内部处理

java 复制代码
// ClassPathBeanDefinitionScanner 扫描包
public int scan(String... basePackages) {
    // 1. 查找候选 Bean(根据 @Component 元注解)
    Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    // 2. 注册 BeanDefinition(解析 @Scope, @Lazy 等)
    for (BeanDefinition candidate : candidates) {
        registerBeanDefinition(candidate);
    }
}

四、BeanDefinition 合并解析

当存在父子 <bean> 定义时:

java 复制代码
<bean id="parent" abstract="true">
    <property name="commonProp" value="common"/>
</bean>
<bean id="child" parent="parent" class="com.example.Child">
    <property name="childProp" value="child"/>
</bean>

Spring 会调用 getMergedBeanDefinition() 将父子定义合并 成一个完整的 RootBeanDefinition

五、解析过程中的扩展点

1. BeanFactoryPostProcessor

java 复制代码
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        BeanDefinition bd = beanFactory.getBeanDefinition("userService");
        bd.setScope("prototype"); // 修改作用域
    }
}

2. BeanDefinitionRegistryPostProcessor

优先于普通 BeanFactoryPostProcessor,可注册新的 BeanDefinition。

3. 自定义 XML 标签解析

java 复制代码
// 实现 NamespaceHandler 和 BeanDefinitionParser
// 在 META-INF/spring.handlers 中注册

六、流程图总结

bash 复制代码
配置文件 (XML/注解/JavaConfig)
         ↓
BeanDefinitionReader 加载
         ↓
解析生成 BeanDefinition (元数据)
         ↓
注册到 BeanDefinitionRegistry
         ↓
BeanFactoryPostProcessor 处理 (修改 BeanDefinition)
         ↓
完成解析,容器持有 BeanDefinition 集合
         ↓
后续用于 Bean 实例化 (getBean 时或预实例化)

七、关键类总结

类名 职责
BeanDefinition 存储 Bean 的元信息
BeanDefinitionReader 从配置源读取并注册 BeanDefinition
BeanDefinitionRegistry 管理 BeanDefinition 的容器
BeanDefinitionParserDelegate 解析 XML 中的 <bean> 元素
ClassPathBeanDefinitionScanner 扫描类路径下的注解 Bean
ConfigurationClassPostProcessor 核心注解配置解析器(处理 @Configuration, @Bean 等)

spring-beans 的解析本质:将配置声明 转换为内存中的 BeanDefinition 对象,为后续的依赖注入和生命周期管理做好准备。理解解析过程有助于掌握 Spring 容器启动的全貌,以及在需要时自定义 Bean 的加载行为。

相关推荐
码农-阿杰2 小时前
生成偏向锁 + JIT
java
czt_java2 小时前
线程安全问题
java·开发语言·jvm
苏三说技术2 小时前
为什么大厂都不推荐在MySQL中使用NULL值?
后端
likerhood2 小时前
设计模式-装饰器模式(java)
java·设计模式·装饰器模式
爱学习的小可爱卢2 小时前
Java抽象类与接口:面试高频考点全解析
java·javase
techdashen2 小时前
Rust 模块和文件不是一回事:一次讲清 `mod`、`use`、`pub use`
开发语言·后端·rust
爱勇宝2 小时前
别焦虑,也别躺平:给年轻程序员的一封信
前端·后端·架构
WL_Aurora2 小时前
Java多线程详解(一)
java·开发语言
会编程的土豆2 小时前
Go 语言中的 `new` 关键字(创建指针)
java·算法·golang