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 的加载行为。

相关推荐
guodingdingh15 分钟前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯2 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
优橙教育2 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
掘金码甲哥2 小时前
这块终端神器, 必须吹爆!
后端
糖果店的幽灵2 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
Csvn3 小时前
📊 SQL 入门 Day 8:集合操作 — 用 SQL 做数学里的"并交差"
后端·sql
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影4 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Miao121315 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔5 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程