【Spring Boot刷新上下文核心流程详解】
Spring Boot 刷新上下文核心流程详解
一、前言
在使用 Spring Boot 启动应用时,控制台会打印出一大串日志,其中最核心的启动动作之一就是 刷新上下文(refresh)。
refresh 方法不仅负责 Bean 的创建与初始化,还涉及监听器、国际化、多环境配置等多个模块,是 Spring Boot 启动的核心环节。
本文将结合源码,带你从入口到细节剖析刷新上下文的全过程。
二、入口位置
实例方法SpringApplication#run
好,那我帮你写一篇**《Spring Boot 刷新上下文核心流程详解》**的 CSDN 博客文章,结构会清晰、逻辑循序渐进,既有源码分析又有配图思路,读者看完能对整个 refresh 流程有一个比较完整的理解。
Spring Boot 刷新上下文核心流程详解
一、前言
在使用 Spring Boot 启动应用时,控制台会打印出一大串日志,其中最核心的启动动作之一就是 刷新上下文(refresh)。
refresh
方法不仅负责 Bean 的创建与初始化,还涉及监听器、国际化、多环境配置等多个模块,是 Spring Boot 启动的核心环节。
本文将结合源码,带你从入口到细节剖析刷新上下文的全过程。
二、入口位置
Spring Boot 的启动入口通常是:
SpringApplication.run(Application.class, args);
调用链简化如下:
SpringApplication.run()-> SpringApplication.refreshContext()-> AbstractApplicationContext.refresh()
核心就在 AbstractApplicationContext.refresh()
方法中,这也是所有 Spring 上下文实现(如 AnnotationConfigServletWebServerApplicationContext
)的基础模板方法。
三、源码流程概览
AbstractApplicationContext# refresh()
的主要执行步骤如下(简化版):
public void refresh() throws BeansException, IllegalStateException {this.startupShutdownLock.lock();try {this.startupShutdownThread = Thread.currentThread();StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);beanPostProcess.end();this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (Error | RuntimeException var12) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var12);}this.destroyBeans();this.cancelRefresh(var12);throw var12;} finally {contextRefresh.end();}} finally {this.startupShutdownThread = null;this.startupShutdownLock.unlock();}}
四、各步骤详解
1. prepareRefresh()
:刷新前准备
- 设置启动时间
- 初始化
active
标志位 - 初始化
PropertySources
(环境变量、配置文件等) - 校验必须的配置
作用:确保上下文环境准备好,避免启动中途缺配置。
2. obtainFreshBeanFactory()
:获取 BeanFactory
整体流程
AbstractRefreshableApplicationContext#obtainFreshBeanFactory()
-->AbstractRefreshableApplicationContext#refreshBeanFactory
-->createBeanFactory()
-->loadBeanDefinitions()
最后执行AnnotationConfigWebApplicationContext#loadBeanDefinitions
(刷新上下文最核心的方法)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {AnnotatedBeanDefinitionReader reader = this.getAnnotatedBeanDefinitionReader(beanFactory);ClassPathBeanDefinitionScanner scanner = this.getClassPathBeanDefinitionScanner(beanFactory);BeanNameGenerator beanNameGenerator = this.getBeanNameGenerator();if (beanNameGenerator != null) {reader.setBeanNameGenerator(beanNameGenerator);scanner.setBeanNameGenerator(beanNameGenerator);beanFactory.registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", beanNameGenerator);}ScopeMetadataResolver scopeMetadataResolver = this.getScopeMetadataResolver();if (scopeMetadataResolver != null) {reader.setScopeMetadataResolver(scopeMetadataResolver);scanner.setScopeMetadataResolver(scopeMetadataResolver);}if (!this.componentClasses.isEmpty()) {if (this.logger.isDebugEnabled()) {this.logger.debug("Registering component classes: [" + StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");}reader.register(ClassUtils.toClassArray(this.componentClasses));}if (!this.basePackages.isEmpty()) {if (this.logger.isDebugEnabled()) {this.logger.debug("Scanning base packages: [" + StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");}scanner.scan(StringUtils.toStringArray(this.basePackages));}
主要流程
- 执行
this.createBeanFactory()
默认bean工厂:DefaultListableBeanFactory实例创建 - 从核心触发
loadBeanDefinitions
触发:创建对应的 BeanDefinition 将其注册到 BeanDefinitionRegistryAnnotatedBeanDefinitionReader#register
方法进行对@Component等注解进行解析注册成对应的 BeanDefinition (bean的元数据,包括bean名称,作用域等,类似注册bean之前得先准备好bean的材料,才能注册)ClassPathBeanDefinitionScanner#scan
方法对 @ComponentScan的basepack进行解析,扫描包路径下的注解注册BeanDefinition。
- 返回对应的DefaultListableBeanFactory工厂实例
3. prepareBeanFactory()
:BeanFactory 预准备
4. postProcessBeanFactory()
:子类扩展
添加相关 Bean 后处理器,为后续创建好的 bean 可做扩展。
5. invokeBeanFactoryPostProcessors()
:调用 BeanFactory 后置处理器
- 先执行
BeanDefinitionRegistryPostProcessor
(可修改 Bean 定义) - 再执行
BeanFactoryPostProcessor
(可修改 BeanFactory 配置)
典型例子:
ConfigurationClassPostProcessor
- 会解析 @Configuration 类:
- 处理 @Bean 方法 → 新注册对应的 BeanDefinition
- 处理 @ComponentScan → 扫描新包,注册新 BeanDefinition
- 处理 @Import、@ImportResource → 引入额外 BeanDefinition,Import其实也是自动装配原理的第一个最重要的一点
流程是
refresh()→ invokeBeanFactoryPostProcessors()中的postProcessBeanDefinitionRegistry()→ ConfigurationClassPostProcessor#processConfigBeanDefinitions()→ ConfigurationClassParser#parse→ ConfigurationClassParser#processImports()→ AutoConfigurationImportSelector#selectImports()
6. registerBeanPostProcessors()
:注册 Bean 后置处理器
- AOP、@Autowired、@ConfigurationProperties 等功能都依赖它
- 会在 Bean 实例化前后执行拦截逻辑
7. initMessageSource()
:国际化
- 如果用户定义了
messageSource
Bean,则使用用户的 - 否则创建
DelegatingMessageSource
作为默认实现
8. initApplicationEventMulticaster()
:事件广播器
- 如果用户定义了
applicationEventMulticaster
,则使用用户的 - 否则创建默认的
SimpleApplicationEventMulticaster
9. onRefresh()
:子类刷新逻辑
- Web 环境下启动
Tomcat/Jetty/Undertow
内嵌容器 - 加载 DispatcherServlet 等 MVC 核心组件
10. registerListeners()
:注册监听器
- 注册所有
ApplicationListener
类型的 Bean - 处理启动前缓存的早期事件
11. finishBeanFactoryInitialization()
:根据实例化所有非懒加载单例
- 根据已有的 BeanDefinition 注册对应的bean
- 依赖注入
- 初始化方法执行(
@PostConstruct
、InitializingBean
等)
12. finishRefresh()
:收尾工作
- 清理缓存
- 发布
ContextRefreshedEvent
- 标记启动完成
五、流程图
prepareRefresh()↓
obtainFreshBeanFactory()↓
prepareBeanFactory()↓
postProcessBeanFactory()↓
invokeBeanFactoryPostProcessors()↓
registerBeanPostProcessors()↓
initMessageSource()↓
initApplicationEventMulticaster()↓
onRefresh()↓
registerListeners()↓
finishBeanFactoryInitialization()↓
finishRefresh()
六、总结
refresh()
就像 Spring Boot 启动的总指挥,控制了从配置准备 → BeanFactory 构建 → Bean 创建 → 事件发布的全流程。
理解它,不仅能帮助我们定位启动问题,还能在做框架扩展、定制化 Bean 加载逻辑时得心应手。