深入剖析Spring Boot应用启动全流程
目录
前言
启动流程概览
一、第一阶段:初始化SpringApplication
二、第二阶段:运行SpringApplication
三、第三阶段:环境准备
四、第四阶段:创建应用上下文
五、第五阶段:准备应用上下文
六、第六阶段:刷新应用上下文(核心)
七、第七阶段:启动后处理
启动流程图解
Spring Boot启动流程与自动装配的联系
总结
前言
Spring Boot以其"开箱即用"的特性大大简化了Spring应用的开发部署流程。只需一个main方法和一个简单的SpringApplication.run()
调用,我们的应用就能快速启动。但这背后究竟发生了什么?本文将深入剖析Spring Boot应用的完整启动流程,带你理解从点击"运行"到应用完全就绪的每一个关键步骤。
启动流程概览
Spring Boot的启动过程可以概括为以下几个核心阶段:
-
初始化SpringApplication实例
-
运行SpringApplication
-
准备环境设置
-
创建应用上下文
-
刷新应用上下文(核心)
-
执行Runner接口实现
下面我们详细分析每个阶段的具体工作。
一、第一阶段:初始化SpringApplication
当我们调用SpringApplication.run(Application.class, args)
时,首先会初始化一个SpringApplication实例
//代码示例
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);
}public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}
在SpringApplication的构造函数中,会进行以下关键操作:
-
推断应用类型:根据类路径下的依赖判断是SERVLET应用(Spring MVC)、REACTIVE应用(WebFlux)还是普通应用
-
加载应用上下文初始化器:通过SpringFactoriesLoader从META-INF/spring.factories加载ApplicationContextInitializer
-
加载应用监听器:同样通过SpringFactoriesLoader加载ApplicationListener
-
推断主配置类:根据堆栈信息找到包含main方法的类
二、第二阶段:运行SpringApplication
run方法是整个启动流程的核心:
public ConfigurableApplicationContext run(String... args) {// 1. 创建启动计时器StopWatch stopWatch = new StopWatch();stopWatch.start();// 2. 初始化默认应用上下文ConfigurableApplicationContext context = null;// 3. 配置headless属性configureHeadlessProperty();// 4. 获取SpringApplicationRunListenersSpringApplicationRunListeners listeners = getRunListeners(args);// 5. 发布应用开始启动事件listeners.starting();try {// 6. 准备环境ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// 7. 打印BannerBanner printedBanner = printBanner(environment);// 8. 创建应用上下文context = createApplicationContext();// 9. 准备应用上下文prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 10. 刷新应用上下文(核心步骤)refreshContext(context);// 11. 上下文刷新后处理afterRefresh(context, applicationArguments);// 12. 停止计时器stopWatch.stop();// 13. 发布应用启动完成事件if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);// 14. 调用ApplicationRunner和CommandLineRunnercallRunners(context, applicationArguments);} catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);} catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;
}
三、第三阶段:环境准备
prepareEnvironment()
方法负责准备应用运行环境:
-
创建环境对象:根据应用类型创建StandardEnvironment或StandardServletEnvironment
-
配置环境:配置PropertySources和Profiles
-
发布环境准备事件:通过EnvironmentPostProcessorApplicationListener处理
-
绑定环境到SpringApplication
-
转换配置:将命令行参数转换为PropertySource
-
处理ConfigurationProperties:验证和绑定@ConfigurationProperties
四、第四阶段:创建应用上下文
createApplicationContext()
根据应用类型创建对应的应用上下文:
-
Servlet应用:AnnotationConfigServletWebServerApplicationContext
-
Reactive应用:AnnotationConfigReactiveWebServerApplicationContext
-
普通应用:AnnotationConfigApplicationContext
五、第五阶段:准备应用上下文
prepareContext()
方法准备创建好的应用上下文:
-
设置环境
-
后处理上下文:调用ApplicationContextInitializer
-
发布上下文准备事件
-
注册SpringBootBanner
-
设置资源加载器和类加载器
-
注册Bean定义:
-
注册主配置类(@SpringBootApplication标注的类)
-
注册命令行参数Bean
-
注册Banner Bean
-
六、第六阶段:刷新应用上下文(核心)
refreshContext()
调用的是AbstractApplicationContext的refresh()方法,这是Spring容器的核心生命周期方法:
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 1. 准备刷新上下文prepareRefresh();// 2. 获取刷新后的BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 3. 准备BeanFactory使用上下文prepareBeanFactory(beanFactory);try {// 4. 允许BeanFactory的后处理postProcessBeanFactory(beanFactory);// 5. 调用BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);// 6. 注册BeanPostProcessorregisterBeanPostProcessors(beanFactory);// 7. 初始化MessageSourceinitMessageSource();// 8. 初始化事件广播器initApplicationEventMulticaster();// 9. 初始化特殊Bean(由子类实现)onRefresh();// 10. 注册监听器registerListeners();// 11. 完成BeanFactory初始化,实例化所有非懒加载单例finishBeanFactoryInitialization(beanFactory);// 12. 完成刷新,发布上下文刷新事件finishRefresh();} catch (BeansException ex) {// 13. 销毁已创建的单例BeandestroyBeans();// 14. 重置激活标志cancelRefresh(ex);throw ex;} finally {// 15. 重置Spring核心中的公共内省缓存resetCommonCaches();}}
}
对于Spring Boot来说,onRefresh()
方法尤为重要,这里会创建嵌入式Web服务器:
protected void onRefresh() {super.onRefresh();try {createWebServer(); // 创建Tomcat、Jetty或Undertow服务器} catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}
}
七、第七阶段:启动后处理
刷新完成后,Spring Boot会执行一些后处理操作:
-
调用ApplicationRunner和CommandLineRunner:执行应用中定义的Runner实现
-
发布应用就绪事件:ApplicationReadyEvent,表示应用已完全启动
-
启动完成:此时应用已完全就绪,可以处理请求
启动流程图解
Spring Boot启动流程与自动装配的联系
1.核心关系:自动装配是启动流程的关键环节
简单来说,自动装配是Spring Boot启动流程中的一个核心子过程。没有启动流程提供的环境、上下文和机制,自动装配无法工作;而没有自动装配,Spring Boot的启动就失去了"智能"和"自动化"的特性,退回到了传统Spring应用的繁琐配置模式。
2.自动装配的具体执行时机
自动装配发生在应用上下文刷新阶段,具体在refreshContext()
方法中的invokeBeanFactoryPostProcessors(beanFactory)
步骤:
public void refresh() throws BeansException, IllegalStateException {// ... 前面的步骤invokeBeanFactoryPostProcessors(beanFactory); // 自动装配在这里发生!// ... 后续步骤
}
总结
Spring Boot的启动流程是一个精心设计的过程,它将传统的XML配置转换为基于Java的自动配置,通过条件化装配和自动发现机制,极大地简化了Spring应用的开发和部署。理解这个流程不仅有助于我们更好地使用Spring Boot,还能在遇到问题时快速定位和解决。
整个过程体现了Spring Boot的核心设计理念:约定优于配置、自动装配和微内核架构。通过事件监听机制和扩展点设计,Spring Boot在保持简洁性的同时,也提供了极大的灵活性和可扩展性。