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. 加载初始化器ApplicationContextInitializer3. 加载监听器ApplicationListener4. 推断主类run() 方法开始5. 准备环境Environment6. 打印Banner7. 创建应用上下文ApplicationContext8. 准备上下文postProcessApplicationContext9. 刷新上下文refreshContext10. 执行RunnerCommandLineRunner11. 发布已启动事件二、两大阶段: 构造与运行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.port8080)); 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启动的全过程欢迎点赞收藏。有任何疑问欢迎评论区交流

本月热点