深入理解 Spring Bean 初始化过程

110 阅读4分钟

Spring 作为业界最广泛使用的 Java 企业级框架,它的 IoC 容器初始化 是整个运行机制的核心。很多人会使用 Spring,但对其启动过程的理解往往停留在表面。本文将从 概念、流程、源码、应用 四个维度,深入剖析 Spring 在初始化类的过程中到底做了什么。


一、核心概念铺垫

在正式进入源码流程前,必须先厘清几个关键概念,否则容易被一堆类名和方法绕晕。

1. ApplicationContext

  • 定义:Spring 的 IoC 容器,是整个框架的核心入口。

  • 作用:负责 bean 的生命周期管理(创建、初始化、销毁)、依赖注入、资源加载、事件发布等。

  • 常见实现

    • ClassPathXmlApplicationContext
    • AnnotationConfigApplicationContext
    • GenericApplicationContext
  • 特点:实现了 BeanFactory,并扩展了大量企业级特性。


2. BeanDefinition

  • 定义:Spring 用于描述 bean 的配置元数据的对象。
  • 内容:包括 bean 的 class 类型、作用域(scope)、依赖注入信息、初始化/销毁方法、是否懒加载等。
  • 本质:bean 的蓝图,存放在 Spring 容器的 注册表(BeanDefinitionRegistry) 中。

3. BeanFactory & BeanDefinitionRegistry

  • BeanFactory:最基本的 IoC 容器接口,定义了获取 bean 的基本规范。
  • BeanDefinitionRegistry:管理 BeanDefinition 的注册表,ApplicationContext 就是它的实现之一。

4. BeanDefinitionLoader

  • 作用:将外部配置(XML、注解、Java 配置类)转换为 BeanDefinition 并注册到容器。
  • 地位:桥梁角色,负责“加载”。

二、Spring 容器的初始化总览

一个 ApplicationContext 的完整初始化,大致可以分为 6 个阶段

  1. 容器创建(构造函数/refresh())

    • 创建基础环境和资源。
  2. BeanDefinition 加载

    • 使用 BeanDefinitionLoader 从 XML/注解等配置源解析 bean 元数据。
  3. BeanDefinition 注册

    • 将解析出的元数据注册到 BeanDefinitionRegistry
  4. BeanFactory 初始化

    • 实例化 DefaultListableBeanFactory,加载并准备 bean 定义。
  5. Bean 实例化 & 依赖注入

    • 根据 BeanDefinition 创建真实的 bean 对象,并完成属性注入。
  6. 后置处理 & 生命周期回调

    • 调用各种 BeanPostProcessor@PostConstructInitializingBean 等。
  7. 容器就绪

    • 进入运行状态,随时可以通过 getBean() 获取实例。

三、分阶段深入剖析

阶段 1:容器创建

AnnotationConfigApplicationContext 为例:

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  • 过程

    1. 调用构造函数,初始化内部的 BeanFactory
    2. 调用 refresh(),开启核心初始化流程。
  • 源码关键点

    • GenericApplicationContext 中持有 DefaultListableBeanFactory
    • refresh() 是 Spring 初始化的总调度方法。

阶段 2:BeanDefinition 加载

  • 核心类

    • AnnotatedBeanDefinitionReader
    • ClassPathBeanDefinitionScanner
  • 过程

    1. 读取配置类(@Configuration 标注的类)。
    2. 解析注解(@ComponentScan@Bean@Import 等)。
    3. 将解析结果包装成 BeanDefinition
  • 示例

    @Configuration
    @ComponentScan("com.example")
    public class AppConfig {
        @Bean
        public UserService userService() {
            return new UserService();
        }
    }
    
    • userService() 会被解析成一个 BeanDefinition,注册到容器中。

阶段 3:BeanDefinition 注册

  • 注册点BeanDefinitionRegistry.registerBeanDefinition(String beanName, BeanDefinition bd)

  • 存储结构ConcurrentHashMap<String, BeanDefinition>

  • 关键逻辑

    • 每个 beanName 与对应的 BeanDefinition 存放在注册表。
    • 这一步只存元数据,还没有实例化对象

阶段 4:BeanFactory 初始化

  • DefaultListableBeanFactory 是 Spring 默认的 BeanFactory 实现。

  • 在此阶段,Spring 会:

    • 处理 bean 定义合并。
    • 检查 bean 依赖关系。
    • 注册 BeanPostProcessor 等扩展。

阶段 5:Bean 实例化 & 依赖注入

当容器准备就绪后,开始创建 bean 对象:

  1. 实例化:通过反射调用构造函数。

  2. 属性注入:根据 @Autowired@Resource 或 XML 配置注入依赖。

  3. Aware 接口回调:如 BeanNameAwareApplicationContextAware

  4. 初始化方法

    • 调用 @PostConstruct
    • 调用 InitializingBean.afterPropertiesSet()
    • 调用配置的 init-method

阶段 6:BeanPostProcessor 扩展

  • 典型用途

    • AOP 动态代理(AnnotationAwareAspectJAutoProxyCreator
    • @Autowired 依赖注入(AutowiredAnnotationBeanPostProcessor
  • 位置

    • 在 bean 初始化前后都会执行。

阶段 7:容器就绪

此时容器已经完成:

  • 所有单例 bean 已经创建并初始化。
  • 可以通过 context.getBean() 获取对象。
  • 事件机制、国际化等企业级特性也已可用。

四、完整流程图

create ApplicationContext
        │
        ▼
     refresh()
        │
        ├─> 1. 创建 BeanFactory
        ├─> 2. 加载 BeanDefinition
        ├─> 3. 注册到 Registry
        ├─> 4. 初始化 BeanFactory
        ├─> 5. 实例化 Bean
        ├─> 6. 调用 BeanPostProcessor
        └─> 7. 容器就绪

五、应用场景与思考

  1. 为什么要有 BeanDefinition?

    • 解耦配置与实例化过程,先存元数据,再灵活创建对象。
  2. 为什么要有 BeanFactory 与 ApplicationContext 的区分?

    • BeanFactory:轻量级,仅提供 IoC 能力。
    • ApplicationContext:企业级容器,包含国际化、事件、AOP 等。
  3. 扩展点在哪里?

    • 自定义 BeanFactoryPostProcessor,修改 bean 定义。
    • 自定义 BeanPostProcessor,增强 bean 行为。

六、总结

Spring 的初始化类过程是一个 分阶段、分职责、层层解耦 的流程。

  • BeanDefinition 负责存储元数据。
  • BeanDefinitionRegistry 负责注册。
  • BeanFactory 负责实例化。
  • ApplicationContext 负责统筹全局。

理解这套机制,不仅有助于读懂源码,还能帮助我们在实际开发中更灵活地运用 Spring 的扩展能力。