Spring 作为业界最广泛使用的 Java 企业级框架,它的 IoC 容器初始化 是整个运行机制的核心。很多人会使用 Spring,但对其启动过程的理解往往停留在表面。本文将从 概念、流程、源码、应用 四个维度,深入剖析 Spring 在初始化类的过程中到底做了什么。
一、核心概念铺垫
在正式进入源码流程前,必须先厘清几个关键概念,否则容易被一堆类名和方法绕晕。
1. ApplicationContext
-
定义:Spring 的 IoC 容器,是整个框架的核心入口。
-
作用:负责 bean 的生命周期管理(创建、初始化、销毁)、依赖注入、资源加载、事件发布等。
-
常见实现:
ClassPathXmlApplicationContextAnnotationConfigApplicationContextGenericApplicationContext
-
特点:实现了
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 个阶段:
-
容器创建(构造函数/refresh())
- 创建基础环境和资源。
-
BeanDefinition 加载
- 使用
BeanDefinitionLoader从 XML/注解等配置源解析 bean 元数据。
- 使用
-
BeanDefinition 注册
- 将解析出的元数据注册到
BeanDefinitionRegistry。
- 将解析出的元数据注册到
-
BeanFactory 初始化
- 实例化
DefaultListableBeanFactory,加载并准备 bean 定义。
- 实例化
-
Bean 实例化 & 依赖注入
- 根据
BeanDefinition创建真实的 bean 对象,并完成属性注入。
- 根据
-
后置处理 & 生命周期回调
- 调用各种
BeanPostProcessor、@PostConstruct、InitializingBean等。
- 调用各种
-
容器就绪
- 进入运行状态,随时可以通过
getBean()获取实例。
- 进入运行状态,随时可以通过
三、分阶段深入剖析
阶段 1:容器创建
以 AnnotationConfigApplicationContext 为例:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
过程:
- 调用构造函数,初始化内部的
BeanFactory。 - 调用
refresh(),开启核心初始化流程。
- 调用构造函数,初始化内部的
-
源码关键点:
GenericApplicationContext中持有DefaultListableBeanFactory。refresh()是 Spring 初始化的总调度方法。
阶段 2:BeanDefinition 加载
-
核心类:
AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner
-
过程:
- 读取配置类(
@Configuration标注的类)。 - 解析注解(
@ComponentScan、@Bean、@Import等)。 - 将解析结果包装成
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存放在注册表。 - 这一步只存元数据,还没有实例化对象。
- 每个 beanName 与对应的
阶段 4:BeanFactory 初始化
-
DefaultListableBeanFactory是 Spring 默认的BeanFactory实现。 -
在此阶段,Spring 会:
- 处理 bean 定义合并。
- 检查 bean 依赖关系。
- 注册
BeanPostProcessor等扩展。
阶段 5:Bean 实例化 & 依赖注入
当容器准备就绪后,开始创建 bean 对象:
-
实例化:通过反射调用构造函数。
-
属性注入:根据
@Autowired、@Resource或 XML 配置注入依赖。 -
Aware 接口回调:如
BeanNameAware、ApplicationContextAware。 -
初始化方法:
- 调用
@PostConstruct - 调用
InitializingBean.afterPropertiesSet() - 调用配置的
init-method
- 调用
阶段 6:BeanPostProcessor 扩展
-
典型用途:
- AOP 动态代理(
AnnotationAwareAspectJAutoProxyCreator) - @Autowired 依赖注入(
AutowiredAnnotationBeanPostProcessor)
- AOP 动态代理(
-
位置:
- 在 bean 初始化前后都会执行。
阶段 7:容器就绪
此时容器已经完成:
- 所有单例 bean 已经创建并初始化。
- 可以通过
context.getBean()获取对象。 - 事件机制、国际化等企业级特性也已可用。
四、完整流程图
create ApplicationContext
│
▼
refresh()
│
├─> 1. 创建 BeanFactory
├─> 2. 加载 BeanDefinition
├─> 3. 注册到 Registry
├─> 4. 初始化 BeanFactory
├─> 5. 实例化 Bean
├─> 6. 调用 BeanPostProcessor
└─> 7. 容器就绪
五、应用场景与思考
-
为什么要有 BeanDefinition?
- 解耦配置与实例化过程,先存元数据,再灵活创建对象。
-
为什么要有 BeanFactory 与 ApplicationContext 的区分?
BeanFactory:轻量级,仅提供 IoC 能力。ApplicationContext:企业级容器,包含国际化、事件、AOP 等。
-
扩展点在哪里?
- 自定义
BeanFactoryPostProcessor,修改 bean 定义。 - 自定义
BeanPostProcessor,增强 bean 行为。
- 自定义
六、总结
Spring 的初始化类过程是一个 分阶段、分职责、层层解耦 的流程。
BeanDefinition负责存储元数据。BeanDefinitionRegistry负责注册。BeanFactory负责实例化。ApplicationContext负责统筹全局。
理解这套机制,不仅有助于读懂源码,还能帮助我们在实际开发中更灵活地运用 Spring 的扩展能力。