Spring容器启动流程
Spring容器的启动流程可以看作是一个精密的装配流水线,其核心目标是根据用户提供的配置元数据(Configuration Metadata),创建、配置并组装应用程序中的对象(Bean),最终形成一个完整的、可用的应用上下文(ApplicationContext)。
下面我将从宏观流程和核心步骤两个层面,并结合关键的源码接口,来详细解释Spring容器的启动流程。
一、宏观流程概述
一个典型的Spring容器(以ClassPathXmlApplicationContext
为例)启动流程可以概括为以下三个大阶段:
- 容器初始化阶段:为启动做准备,设置环境变量、资源解析器等。
- Bean加载与解析阶段(核心中的核心):读取配置元数据,将其解析为容器内部数据结构(
BeanDefinition
)。 - Bean实例化与依赖注入阶段:根据
BeanDefinition
的信息,通过反射创建Bean实例,并解决其依赖关系。 - 后处理与完成阶段:执行相关的后处理器,触发生命周期回调,发布上下文就绪事件。
为了更直观地理解,下图描绘了这个过程的核心步骤与迭代循环:
flowchart TD A[Spring容器启动流程] --> B[初始化阶段
创建Context、加载配置] B --> C[加载与解析阶段
读取配置→BeanDefinition] C --> D[实例化与注入阶段
(核心循环开始)] subgraph D [Bean创建循环] D1[实例化 Bean
(调用构造函数)] D2[填充属性
(依赖注入)] D3[处理 Aware 接口] D4[BeanPostProcessor前置处理] D5[初始化方法
(InitializingBean, init-method)] D6[BeanPostProcessor后置处理
(AOP在此发生)] end D --> E[所有单例Bean创建完成?] E -- 否 --> D E -- 是 --> F[完成阶段
发布ContextRefreshedEvent] F --> G[应用运行
容器就绪]
二、详细核心步骤分解(以AnnotationConfigApplicationContext为例)
让我们沿着图中所示的流程,深入每个步骤的细节。
阶段一:容器初始化
- 入口:调用
ApplicationContext
的构造方法,例如new AnnotationConfigApplicationContext(AppConfig.class)
。 - 动作:
- 实例化一个
AnnotatedBeanDefinitionReader
,它知道如何解析带有@Configuration
、@Component
等注解的类。 - 实例化一个
ClassPathBeanDefinitionScanner
,用于扫描类路径下的组件(如果配置了组件扫描)。 - 调用
register(componentClasses)
,将配置类注册到容器中。此时,配置类本身也被注册为一个BeanDefinition
。
- 实例化一个
阶段二:Bean加载与解析(refresh()
方法)
调用ApplicationContext
的refresh()
方法是整个启动流程的核心入口和总指挥。这个方法定义在ConfigurableApplicationContext
接口中,包含了启动、刷新、停止容器的完整生命周期。以下是refresh()
方法中最重要的11个步骤:
prepareRefresh()
- 准备刷新- 设置容器的启动日期和活跃状态。
- 初始化占位符属性源(Property Sources)。
- 验证所有必需的属性是否可解析。
obtainFreshBeanFactory()
- 获取BeanFactory- 对于
AnnotationConfigApplicationContext
:刷新或创建一个新的GenericApplicationContext
内部持有的DefaultListableBeanFactory
。这是Bean定义注册和管理的核心容器。 - 对于
ClassPathXmlApplicationContext
:会在这里创建一个新的BeanFactory
(通常是DefaultListableBeanFactory
),然后调用loadBeanDefinitions(beanFactory)
来通过XmlBeanDefinitionReader
加载和解析XML文件。
- 对于
prepareBeanFactory(beanFactory)
- 准备BeanFactory- 配置BeanFactory的标准上下文特性,如
ClassLoader
、SpEL
表达式解析器、属性编辑器注册器等。 - 添加一些内置的
BeanPostProcessor
,例如ApplicationContextAwareProcessor
,用于处理各种*Aware接口。
- 配置BeanFactory的标准上下文特性,如
postProcessBeanFactory(beanFactory)
- 后处理BeanFactory(扩展点)- 这是一个空的模板方法,允许子类在Bean定义加载完成之前,对BeanFactory进行进一步的定制和扩展。例如,
WebApplicationContext
会在这里添加Servlet相关的Scope。
- 这是一个空的模板方法,允许子类在Bean定义加载完成之前,对BeanFactory进行进一步的定制和扩展。例如,
invokeBeanFactoryPostProcessors(beanFactory)
- 执行BeanFactoryPostProcessor- 这是非常关键的一步。它会实例化并调用所有
BeanFactoryPostProcessor
和BeanDefinitionRegistryPostProcessor
。 - 这些处理器允许在Bean实例化之前修改应用程序上下文的Bean定义(即修改
BeanDefinition
)。 - 常见例子:
ConfigurationClassPostProcessor
:处理@Configuration
类,解析其中的@Bean
、@Import
、@ComponentScan
等注解,并将扫描到的Bean注册到容器中。这是注解驱动配置的核心。PropertySourcesPlaceholderConfigurer
:处理占位符${...}
,从属性文件中加载值。
- 这是非常关键的一步。它会实例化并调用所有
registerBeanPostProcessors(beanFactory)
- 注册BeanPostProcessor- 实例化、注册所有
BeanPostProcessor
。注意,此时只是注册,调用发生在Bean实例化过程中。 BeanPostProcessor
是Bean的后置处理器,在Bean的初始化方法调用前后进行拦截,可以修改或包装Bean实例。AOP的动态代理就是通过AnnotationAwareAspectJAutoProxyCreator
(它是一个BeanPostProcessor
)在这里被注册,并在后续步骤中生效的。
- 实例化、注册所有
initMessageSource()
- 初始化消息源- 初始化MessageSource组件,用于国际化(i18n)消息处理。
initApplicationEventMulticaster()
- 初始化事件广播器- 初始化事件广播器(
ApplicationEventMulticaster
),用于支持Spring的事件发布-订阅模型。
- 初始化事件广播器(
onRefresh()
- 模板方法(扩展点)- 又一个空的模板方法,允许特定的上下文子类初始化其他特殊的Bean。例如,Spring Boot的
EmbeddedWebApplicationContext
会在这里创建内嵌的Web服务器(Tomcat, Jetty)。
- 又一个空的模板方法,允许特定的上下文子类初始化其他特殊的Bean。例如,Spring Boot的
registerListeners()
- 注册监听器- 将实现了
ApplicationListener
接口的监听器Bean注册到前面初始化的事件广播器中。 - 也会发布那些在早期步骤中产生的“早期应用事件”。
- 将实现了
阶段三:Bean实例化与依赖注入
finishBeanFactoryInitialization(beanFactory)
- 完成BeanFactory的初始化(实例化所有非懒加载的单例Bean)- 这是另一个最核心的步骤。容器会在这里预实例化所有单例且非懒加载的Bean。
- 流程(即Bean的生命周期)对于每一个Bean如下:
- 实例化(Instantiate):通过反射(通常是无参或有参构造器)创建Bean的实例。
- 填充属性(Populate properties):根据配置(如
@Autowired
,@Value
)进行依赖注入(Dependency Injection, DI)。 - 处理Aware接口:如果Bean实现了各种
Aware
接口(如BeanNameAware
,BeanFactoryAware
,ApplicationContextAware
),则调用其setter方法注入相关对象。 BeanPostProcessor.postProcessBeforeInitialization()
:在初始化方法调用前,执行所有BeanPostProcessor
的预处理。- 初始化(Initialize):
- 如果Bean实现了
InitializingBean
接口,调用其afterPropertiesSet()
方法。 - 调用自定义的初始化方法(通过
@Bean(initMethod="...")
或XML中的init-method
指定)。
- 如果Bean实现了
BeanPostProcessor.postProcessAfterInitialization()
:在初始化方法调用后,执行所有BeanPostProcessor
的后处理。AOP代理就是在此处生成的! 如果发现有切面匹配这个Bean,则会返回一个代理对象来包装目标Bean。- 此时,一个完整的、经过所有处理的Bean就已经存在于容器中了。
阶段四:完成与发布
finishRefresh()
- 完成刷新- 初始化生命周期处理器(
LifecycleProcessor
)。 - 发布容器刷新事件(
ContextRefreshedEvent
),通知所有监听器容器已经准备就绪。 - 调用生命周期处理器的
onRefresh()
方法。
- 初始化生命周期处理器(
容器运行
- 此时,Spring容器已经完全启动,所有单例Bean都已创建并装配完毕,应用程序可以正常运行。可以通过
context.getBean(...)
来获取Bean并使用。
- 此时,Spring容器已经完全启动,所有单例Bean都已创建并装配完毕,应用程序可以正常运行。可以通过
三、总结与关键点
refresh()
方法是核心:它驱动了整个容器的启动流程。BeanDefinition
是蓝图:容器并不直接处理你的Bean类,而是先将其解析为内部的BeanDefinition
数据结构。- 扩展点无处不在:
BeanFactoryPostProcessor
:修改Bean的定义(配置元数据)。BeanPostProcessor
:修改Bean的实例(包装、代理等)。- 各种
Aware
接口:让Bean能感知到容器。
- Bean的生命周期是复杂的:从定义到可用,经历了构造、注入、aware回调、init方法、前后置处理等多个步骤。
- AOP代理发生得较晚:它是在Bean实例化、属性注入之后,通过
BeanPostProcessor
在初始化阶段后期生成的。