当前位置: 首页 > news >正文

Spring Boot启动过程: 从new SpringApplication到run(),这中间到底发生了什么?

Spring Boot启动过程: 从new SpringApplication到run(),这中间到底发生了什么?


引言: 一行代码背后的千山万水


每个Spring Boot应用的入口都是这样一行代码:


SpringApplication.run(Application.class, args);


看似简单,背后却是Spring团队十余年的设计积累。从推断应用类型到加载自动配置,从启动内嵌Web服务器到刷新应用上下文,整个过程涉及数十个步骤和扩展点。


理解这个启动流程,不仅能让你在面试中对答如流,更能在排查启动故障、优化启动性能、扩展框架功能时游刃有余。


本文将完整的启动过程拆解为11个关键步骤,配合源码分析和时序图,让你彻底掌握Spring Boot的启动魔法。


一、启动流程全景图


new SpringApplication()

1. 推断应用类型

2. 加载初始化器
ApplicationContextInitializer

3. 加载监听器
ApplicationListener

4. 推断主类

run() 方法开始

5. 准备环境
Environment

6. 打印Banner

7. 创建应用上下文
ApplicationContext

8. 准备上下文
postProcessApplicationContext

9. 刷新上下文
refreshContext

10. 执行Runner
CommandLineRunner

11. 发布已启动事件


二、两大阶段: 构造与运行


WebServerApplicationContextEnvironmentSpringApplicationmain方法WebServerApplicationContextEnvironmentSpringApplicationmain方法=== 阶段1: new SpringApplication() ====== 阶段2: run() ===new SpringApplication(primarySources)1. 推断应用类型(WebFlux/Servlet/None)2. 加载ApplicationContextInitializer3. 加载ApplicationListener4. 推断主类(main方法所在类)run(args)5. 创建并准备Environment6. 创建ApplicationContext7. 准备上下文8. 刷新上下文(Spring核心启动)9. 启动内嵌Web服务器10. 执行Runner11. 返回上下文


三、详细步骤拆解


3.1 步骤1: 推断应用类型


/** * SpringApplication 构造器中第一步: 推断应用类型 */ public class Step1_InferApplicationType { // 源码位置: SpringApplication.deduceWebApplicationType() // // private WebApplicationType deduceWebApplicationType() { // // 检查类路径中是否存在特定类 // if (ClassUtils.isPresent( // "org.springframework.web.reactive.DispatcherHandler", null) // && !ClassUtils.isPresent( // "org.springframework.web.servlet.DispatcherServlet", null)) { // return WebApplicationType.REACTIVE; // WebFlux // } // for (String className : SERVLET_INDICATOR_CLASSES) { // if (!ClassUtils.isPresent(className, null)) { // return WebApplicationType.NONE; // 非Web应用 // } // } // return WebApplicationType.SERVLET; // Servlet Web(默认) // } public static void main(String[] args) { System.out.println("=== 推断应用类型 ===\n"); System.out.println("判断逻辑:"); System.out.println("1. 有 DispatcherHandler 且无 DispatcherServlet"); System.out.println(" -> REACTIVE (WebFlux应用)"); System.out.println("2. 缺少 javax.servlet.Servlet 或 DispatcherServlet"); System.out.println(" -> NONE (非Web应用)"); System.out.println("3. 其他情况"); System.out.println(" -> SERVLET (传统Servlet Web应用)\n"); System.out.println("这个判断决定了:"); System.out.println("- 创建哪种 ApplicationContext"); System.out.println("- 是否启动内嵌Web服务器"); System.out.println("- 加载哪些Web相关的自动配置"); } }


3.2 步骤2-3: 加载初始化器与监听器(SPI机制)


/** * SpringApplication 构造器第二步、第三步 * 通过 SpringFactoriesLoader 加载初始化器和监听器 */ public class Step2_LoadInitializersAndListeners { // 源码位置: SpringApplication 构造器 // // public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // this.resourceLoader = resourceLoader; // this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // this.webApplicationType = deduceWebApplicationType(); // // // 步骤2: 从spring.factories加载初始化器 // this.bootstrapRegistryInitializers = // getBootstrapRegistryInitializersFromSpringFactories(); // setInitializers( // getSpringFactoriesInstances(ApplicationContextInitializer.class)); // // // 步骤3: 从spring.factories加载监听器 // setListeners( // getSpringFactoriesInstances(ApplicationListener.class)); // // // 步骤4: 推断主类 // this.mainApplicationClass = deduceMainApplicationClass(); // } public static void main(String[] args) { System.out.println("=== 加载初始化器与监听器 ===\n"); System.out.println("加载机制: SpringFactoriesLoader"); System.out.println("从所有jar包的 META-INF/spring.factories 中读取\n"); System.out.println("spring-boot.jar!/META-INF/spring.factories 内容:"); System.out.println("ApplicationContextInitializer:\\"); System.out.println(" org.springframework.boot.context."); System.out.println(" ConfigurationWarningsApplicationContextInitializer,\\"); System.out.println(" org.springframework.boot.context."); System.out.println(" ContextIdApplicationContextInitializer,\\"); System.out.println(" ...\n"); System.out.println("ApplicationListener:\\"); System.out.println(" org.springframework.boot.context.config."); System.out.println(" ConfigFileApplicationListener,\\"); System.out.println(" org.springframework.boot.context.logging."); System.out.println(" LoggingApplicationListener,\\"); System.out.println(" ...\n"); System.out.println("这些组件在启动各阶段被回调,实现功能扩展"); } }


3.3 步骤4: 推断主类


/** * 推断主类: 通过调用栈找到main方法所在的类 */ public class Step4_DeduceMainClass { // 源码逻辑: // private Class<?> deduceMainApplicationClass() { // try { // StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); // for (StackTraceElement element : stackTrace) { // if ("main".equals(element.getMethodName())) { // return Class.forName(element.getClassName()); // } // } // } catch (ClassNotFoundException e) { // // 忽略 // } // return null; // } public static void main(String[] args) { System.out.println("=== 推断主类 ===\n"); System.out.println("方法: 创建一个RuntimeException,分析调用栈"); System.out.println("查找: 栈中包含 'main' 方法的类"); System.out.println("结果: 就是 @SpringBootApplication 标注的类\n"); System.out.println("作用:"); System.out.println("- 作为primarySources传递给ApplicationContext"); System.out.println("- 用于日志输出和Banner信息"); } }


3.4 步骤5: 准备环境


/** * run() 方法中的关键步骤: 准备Environment */ public class Step5_PrepareEnvironment { // 源码: SpringApplication.prepareEnvironment() // // private ConfigurableEnvironment prepareEnvironment( // SpringApplicationRunListeners listeners, // DefaultBootstrapContext bootstrapContext, // ApplicationArguments applicationArguments) { // // // 5.1 创建Environment // ConfigurableEnvironment environment = getOrCreateEnvironment(); // // // 5.2 配置Environment // configureEnvironment(environment, applicationArguments.getSourceArgs()); // // // 5.3 将"spring.main"的配置绑定到SpringApplication // ConfigurationPropertySources.attach(environment); // // // 5.4 发布环境准备事件 // listeners.environmentPrepared(bootstrapContext, environment); // // // 5.5 将"spring.main"配置应用到SpringApplication // DefaultPropertiesPropertySource.moveToEnd(environment); // // return environment; // } public static void main(String[] args) { System.out.println("=== 准备Environment ===\n"); System.out.println("子步骤:"); System.out.println("5.1 创建Environment(Standard或Reactive)"); System.out.println("5.2 配置PropertySources和Profiles"); System.out.println(" - 读取命令行参数(--server.port=8080)"); System.out.println(" - 设置激活的Profile(spring.profiles.active)"); System.out.println("5.3 附加ConfigurationPropertySources"); System.out.println("5.4 发布ApplicationEnvironmentPreparedEvent"); System.out.println(" -> ConfigFileApplicationListener 在此读取 application.yml"); System.out.println("5.5 应用 spring.main 配置到 SpringApplication\n"); System.out.println("关键: application.yml/properties 文件在此阶段加载!"); } }


3.5 步骤6-7: 创建并准备上下文


/** * 创建应用上下文并准备 */ public class Step6_CreateAndPrepareContext { // 源码: SpringApplication.createApplicationContext() // // protected ConfigurableApplicationContext createApplicationContext() { // return this.applicationContextFactory.create(this.webApplicationType); // } // // 根据webApplicationType创建不同的上下文: // SERVLET -> AnnotationConfigServletWebServerApplicationContext // REACTIVE -> AnnotationConfigReactiveWebServerApplicationContext // NONE -> AnnotationConfigApplicationContext public static void main(String[] args) { System.out.println("=== 创建并准备上下文 ===\n"); System.out.println("步骤6: 创建ApplicationContext"); System.out.println(" 根据推断的类型创建对应的上下文实现\n"); System.out.println("步骤7: prepareContext - 准备上下文"); System.out.println(" 7.1 设置Environment"); System.out.println(" 7.2 后置处理(postProcessApplicationContext)"); System.out.println(" 7.3 执行ApplicationContextInitializer"); System.out.println(" 7.4 发布ApplicationContextInitializedEvent"); System.out.println(" 7.5 注册启动源(primarySources)"); System.out.println(" 7.6 发布ApplicationPreparedEvent"); } }


3.6 步骤8: 刷新上下文(Spring核心启动)


/** * refreshContext: Spring Framework的核心启动流程 * * 这是整个启动过程中最关键、最复杂的步骤 */ public class Step8_RefreshContext { // 源码: SpringApplication.refreshContext() // -> AbstractApplicationContext.refresh() // // public void refresh() throws BeansException { // synchronized (this.startupShutdownMonitor) { // // 1. 准备刷新 // prepareRefresh(); // // // 2. 获取BeanFactory // ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // // // 3. 准备BeanFactory // prepareBeanFactory(beanFactory); // // // 4. BeanFactory后置处理 // postProcessBeanFactory(beanFactory); // // // 5. 执行BeanFactoryPostProcessor // invokeBeanFactoryPostProcessors(beanFactory); // // 这里会执行 ConfigurationClassPostProcessor // // 完成 @Configuration 类的解析和 @ComponentScan // // // 6. 注册BeanPostProcessor // registerBeanPostProcessors(beanFactory); // // // 7. 初始化MessageSource // initMessageSource(); // // // 8. 初始化事件广播器 // initApplicationEventMulticaster(); // // // 9. 子类扩展点(onRefresh) // onRefresh(); // // ServletWebServerApplicationContext 在这里启动内嵌Web服务器! // // // 10. 注册监听器 // registerListeners(); // // // 11. 实例化所有非懒加载的单例Bean // finishBeanFactoryInitialization(beanFactory); // // @Service、@Controller、@Repository 等Bean在这里创建 // // // 12. 完成刷新 // finishRefresh(); // } // } public static void main(String[] args) { System.out.println("=== refresh() 12个核心步骤 ===\n"); System.out.println("1. prepareRefresh()"); System.out.println(" - 设置启动时间、状态标记"); System.out.println(" - 验证必要属性\n"); System.out.println("2. obtainFreshBeanFactory()"); System.out.println(" - 获取BeanFactory(Spring容器)\n"); System.out.println("3. prepareBeanFactory()"); System.out.println(" - 设置类加载器、表达式解析器"); System.out.println(" - 注册默认BeanPostProcessor\n"); System.out.println("4. postProcessBeanFactory()"); System.out.println(" - 子类扩展点(Web上下文扫描特殊Bean)\n"); System.out.println("5. invokeBeanFactoryPostProcessors() ★★★"); System.out.println(" - 执行所有BeanFactoryPostProcessor"); System.out.println(" - ConfigurationClassPostProcessor 解析 @Configuration"); System.out.println(" - @ComponentScan 扫描Bean定义"); System.out.println(" - @EnableAutoConfiguration 加载自动配置"); System.out.println(" - 这是自动配置生效的关键步骤!\n"); System.out.println("6. registerBeanPostProcessors()"); System.out.println(" - 注册BeanPostProcessor到容器\n"); System.out.println("7-10. 初始化辅助组件"); System.out.println(" - MessageSource、事件广播器、Web服务器\n"); System.out.println("11. finishBeanFactoryInitialization() ★★★"); System.out.println(" - 实例化所有单例Bean"); System.out.println(" - 处理循环依赖(三级缓存)"); System.out.println(" - 这是最耗时的步骤!\n"); System.out.println("12. finishRefresh()"); System.out.println(" - 发布ContextRefreshedEvent"); } }


3.7 步骤9: 启动内嵌Web服务器


/** * Web服务器启动细节 */ public class Step9_StartWebServer { // 源码: ServletWebServerApplicationContext.onRefresh() // -> createWebServer() // -> webServer.start() // // private void createWebServer() { // WebServer webServer = this.webServer; // ServletContext servletContext = getServletContext(); // if (webServer == null && servletContext == null) { // // 获取WebServerFactory(如TomcatServletWebServerFactory) // ServletWebServerFactory factory = getWebServerFactory(); // // // 创建Web服务器(内嵌Tomcat/Jetty/Undertow) // this.webServer = factory.getWebServer(getSelfInitializer()); // } // // 启动Web服务器 // initPropertySources(); // } public static void main(String[] args) { System.out.println("=== 启动内嵌Web服务器 ===\n"); System.out.println("触发时机: refresh() 中的 onRefresh() 步骤\n"); System.out.println("执行流程:"); System.out.println("1. 获取 ServletWebServerFactory Bean"); System.out.println(" - 根据类路径自动选择:"); System.out.println(" * Tomcat: spring-boot-starter-web 默认"); System.out.println(" * Jetty: 排除Tomcat,引入Jetty"); System.out.println(" * Undertow: 排除Tomcat,引入Undertow"); System.out.println("2. 创建 WebServer 实例"); System.out.println("3. 配置 Servlet、Filter、Listener"); System.out.println("4. 调用 webServer.start() 启动服务"); System.out.println("5. 发布 ServletWebServerInitializedEvent\n"); System.out.println("服务器启动后:"); System.out.println("- 端口已绑定"); System.out.println("- DispatcherServlet 已就绪"); System.out.println("- 可以接收HTTP请求"); } }


3.8 步骤10-11: Runner与完成事件


/** * 启动的最后步骤: 执行Runner并发布完成事件 */ public class Step10_RunnersAndFinish { // 源码: SpringApplication.callRunners() // -> ApplicationRunner.run() 和 CommandLineRunner.run() public static void main(String[] args) { System.out.println("=== 执行Runner ===\n"); System.out.println("Runner执行顺序:"); System.out.println("1. ApplicationRunner (优先级高)"); System.out.println(" - 接收 ApplicationArguments (已解析的参数)"); System.out.println("2. CommandLineRunner (优先级低)"); System.out.println(" - 接收 String[] (原始参数)\n"); System.out.println("使用示例:"); System.out.println("@Component"); System.out.println("public class DataInitializer implements CommandLineRunner {"); System.out.println(" public void run(String... args) {"); System.out.println(" // 初始化数据、预热缓存"); System.out.println(" }"); System.out.println("}\n"); System.out.println("最后: 发布 ApplicationStartedEvent"); System.out.println(" 发布 ApplicationReadyEvent"); System.out.println(" Spring Boot启动完成!"); } }


四、扩展点时机汇总


/** * Spring Boot启动过程的完整扩展点 */ public class ExtensionPointsSummary { public static void main(String[] args) { System.out.println("=== 启动过程扩展点执行顺序 ===\n"); String[] timeline = { "1. SpringApplicationRunListener.starting()", "2. ApplicationContextInitializer.initialize()", "3. SpringApplicationRunListener.environmentPrepared()", "4. SpringApplicationRunListener.contextPrepared()", "5. SpringApplicationRunListener.contextLoaded()", "", "=== refresh() 阶段 ===", "6. BeanFactoryPostProcessor.postProcessBeanFactory()", "7. @PostConstruct", "8. InitializingBean.afterPropertiesSet()", "9. BeanPostProcessor (贯穿Bean创建过程)", "", "=== refresh() 之后 ===", "10. SpringApplicationRunListener.started()", "11. ApplicationRunner.run()", "12. CommandLineRunner.run()", "13. SpringApplicationRunListener.ready()", }; for (String step : timeline) { System.out.println(step); } } }


五、面试高频问题


5.1 启动过程核心面试题


/** * 面试高频问题与答案 */ public class InterviewQuestions { public static void main(String[] args) { System.out.println("=== 面试高频问题 ===\n"); // Q1 System.out.println("Q1: Spring Boot启动过程?"); System.out.println("A: 两大阶段11步:"); System.out.println(" 构造阶段: 推断类型、加载初始化器/监听器、推断主类"); System.out.println(" 运行阶段: 准备环境、创建上下文、准备上下文、"); System.out.println(" 刷新上下文(Spring核心)、启动Web服务器、"); System.out.println(" 执行Runner、发布完成事件\n"); // Q2 System.out.println("Q2: 自动配置什么时候生效?"); System.out.println("A: refresh()的invokeBeanFactoryPostProcessors()步骤"); System.out.println(" ConfigurationClassPostProcessor 解析 @EnableAutoConfiguration"); System.out.println(" -> AutoConfigurationImportSelector 加载 spring.factories"); System.out.println(" -> 条件过滤后注册自动配置类的Bean定义\n"); // Q3 System.out.println("Q3: Web服务器什么时候启动?"); System.out.println("A: refresh()的onRefresh()步骤"); System.out.println(" ServletWebServerApplicationContext 会在此创建并启动"); System.out.println(" 内嵌Tomcat/Jetty/Undertow\n"); // Q4 System.out.println("Q4: application.yml什么时候加载?"); System.out.println("A: 准备环境阶段(步骤5)"); System.out.println(" ConfigFileApplicationListener 监听到环境准备事件"); System.out.println(" 读取 application.yml/properties 并添加到Environment"); } }


六、总结


6.1 启动过程核心步骤速查


| 步骤 | 做什么 | 关键点 |

|------|--------|--------|

| 推断类型 | 检查类路径 | 决定Context和WebServer类型 |

| 加载SPI组件 | 读spring.factories | 初始化器和监听器 |

| 准备环境 | 创建Environment | 加载application.yml |

| 创建上下文 | 根据类型new | 三种Context实现 |

| 准备上下文 | 设置属性 | 执行初始化器 |

|刷新上下文|refresh()|Bean扫描、自动配置、单例实例化|

| 启动WebServer | onRefresh() | 内嵌Tomcat启动 |

| 执行Runner | callRunners() | CommandLineRunner |


6.2 关键类关系图


SpringApplication ├── 创建时: 加载Initializer和Listener └── run()时: ├── 创建Environment ├── 创建ApplicationContext │ └── refresh() │ ├── BeanFactoryPostProcessor (自动配置生效) │ ├── onRefresh() (WebServer启动) │ └── finishBeanFactoryInitialization() (Bean实例化) └── 发布Ready事件


---


如果本文帮你理解了Spring Boot启动的全过程,欢迎点赞收藏。有任何疑问,欢迎评论区交流!



http://www.jsqmd.com/news/1249193/

相关文章:

  • 【单片机毕业设计推荐】 基于 STM32 或 51 单片机的智能感应自动门控制系统设计与实现,基于 STM32 或 51 单片机的带人数统计功能智能门禁装置设计(012403)
  • 零基础自学攻防 11 大步骤,网络安全新手入门至精通全方位干货分析,学习网安留存这一篇即可
  • IPv6相关知识(smb/ssh/scp/浏览器访问)及碰到的坑
  • 国产军事仿真平台如何突破AFSIM二次开发与分布式仿真瓶颈 - 品研笔录
  • 塑料挤出制杯一体化设备怎么选?别只看参数,先搞清工艺匹配、成本结构和交付边界 - 中国品牌价值观察网
  • openwrt软路由(x86-64 koolshare mod)下利用Docker部署guacamole
  • 集团数据质量管控体系建设(数据治理)
  • 下载软件 (三) openocd 的编译
  • 从技术层级角度看多链路聚合通信技术
  • TM4C129LNCZAD UART识别寄存器与QSSI模块深度解析与实战
  • Agentic AI、AI Agent、AI 工作流有什么区别?
  • 为什么提示没有changid?
  • 基于ThreeJs的一些开源地图项目
  • 2026 年 7 月最新丨多品牌 AGV 与提升机第三方统一运维管理指南 - 品牌测评网
  • 2026枣庄300型风厂家哪家好,400型风机厂家推荐避坑指南:4个挑选要点,帮你绕开90%的坑 - mobible
  • 数字人口型同步为何总延迟300ms?揭秘行业TOP3厂商不敢公开的6个底层技术陷阱
  • 静态路由综合练习
  • 如何使用Windows OVERLAPPED优化你的应用
  • 2026北京名包“非专柜渠道”回收警示:代购包、奥莱款、折扣村货,回收时被区别对待吗? - 日常财经早知道
  • C++性能分析
  • TM4C129LNCZAD低功耗模式实战:从架构解析到代码实现
  • TM4C129 UART模块深度解析:从寄存器配置到DMA与中断优化
  • 生态修复理念下广州沙坑涌大源段河道景观提升设计
  • 计算机Django毕设实战-基于Django 的物流物资配送信息管理系统 企业物资出入库与配送调度系统设计【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 华为网络计算机ct2000,第八集[达特分享]华为CT5000一键刷BIOS安装OpenWRT制作软路由...
  • C++高并发内存池:三层架构设计与性能优化实践
  • AI驱动的电商运营革命(2024黑盒策略首次公开):头部品牌已用它悄悄跑赢92%同行
  • TMS320C5000 DMA高级应用实战:数据排序、程序分页与乒乓缓冲详解
  • double浮点数计算的一些问题,以及bigDecimal的使用,和DecimalFormat的对比、Long
  • 2026年实测:宁波4大周末语文小升初机构综合评测