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

深入剖析Spring Boot应用启动全流程

目录

前言

启动流程概览

一、第一阶段:初始化SpringApplication

二、第二阶段:运行SpringApplication

三、第三阶段:环境准备

四、第四阶段:创建应用上下文

五、第五阶段:准备应用上下文

六、第六阶段:刷新应用上下文(核心)

七、第七阶段:启动后处理

启动流程图解

Spring Boot启动流程与自动装配的联系

总结


前言

        Spring Boot以其"开箱即用"的特性大大简化了Spring应用的开发部署流程。只需一个main方法和一个简单的SpringApplication.run()调用,我们的应用就能快速启动。但这背后究竟发生了什么?本文将深入剖析Spring Boot应用的完整启动流程,带你理解从点击"运行"到应用完全就绪的每一个关键步骤。


启动流程概览

Spring Boot的启动过程可以概括为以下几个核心阶段:

  1. 初始化SpringApplication实例

  2. 运行SpringApplication

  3. 准备环境设置

  4. 创建应用上下文

  5. 刷新应用上下文(核心)

  6. 执行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的构造函数中,会进行以下关键操作:

  1. 推断应用类型:根据类路径下的依赖判断是SERVLET应用(Spring MVC)、REACTIVE应用(WebFlux)还是普通应用

  2. 加载应用上下文初始化器:通过SpringFactoriesLoader从META-INF/spring.factories加载ApplicationContextInitializer

  3. 加载应用监听器:同样通过SpringFactoriesLoader加载ApplicationListener

  4. 推断主配置类:根据堆栈信息找到包含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()方法负责准备应用运行环境:

  1. 创建环境对象:根据应用类型创建StandardEnvironment或StandardServletEnvironment

  2. 配置环境:配置PropertySources和Profiles

  3. 发布环境准备事件:通过EnvironmentPostProcessorApplicationListener处理

  4. 绑定环境到SpringApplication

  5. 转换配置:将命令行参数转换为PropertySource

  6. 处理ConfigurationProperties:验证和绑定@ConfigurationProperties

四、第四阶段:创建应用上下文

createApplicationContext()根据应用类型创建对应的应用上下文:

  • Servlet应用:AnnotationConfigServletWebServerApplicationContext

  • Reactive应用:AnnotationConfigReactiveWebServerApplicationContext

  • 普通应用:AnnotationConfigApplicationContext

五、第五阶段:准备应用上下文

prepareContext()方法准备创建好的应用上下文:

  1. 设置环境

  2. 后处理上下文:调用ApplicationContextInitializer

  3. 发布上下文准备事件

  4. 注册SpringBootBanner

  5. 设置资源加载器和类加载器

  6. 注册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会执行一些后处理操作:

  1. 调用ApplicationRunner和CommandLineRunner:执行应用中定义的Runner实现

  2. 发布应用就绪事件:ApplicationReadyEvent,表示应用已完全启动

  3. 启动完成:此时应用已完全就绪,可以处理请求

启动流程图解

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在保持简洁性的同时,也提供了极大的灵活性和可扩展性。

http://www.dtcms.com/a/347595.html

相关文章:

  • MySQL GPG 密钥更新问题解决文档
  • Centos7.9 Docker26容器化部署 MySql9.4 一主一从的同步复制部署
  • 【51单片机非精准延时演示来回流水灯效果】2022-11-10
  • 【机器学习深度学习】自然语言与多模态大模型
  • 【KO】前端面试一
  • git的工作使用中实际经验
  • 关于Highcharts的数据参考与产品系列
  • Camera performance analysis
  • 智能系统与未来生态演进初步思考
  • 告别图片背景违和!autohue.js 让图片与背景自动 “无缝衔接”
  • 基于51单片机自动智能浇花系统设计
  • 【序列晋升】13 Spring Cloud Bus微服务架构中的消息总线
  • 研究生方向:在传统赛道与交叉领域间寻找破局之路
  • 第三阶段数据库-2:数据库中的sql语句
  • 重审文字的本体论地位:符号学转向、解构主义突围与视觉性革命
  • 1电吉他环境搭建:效果器再探
  • C++算法题—— 小C的细菌(二维偏序离线 + 树状数组 + 坐标压缩)
  • [激光原理与应用-328]:结构设计 - Solidworks - 什么是结构建模?
  • PCB电路设计学习3 电路原理图设计 元件PCB封装设计与添加
  • 学习嵌入式第三十六天
  • 神经网络|(十三)概率论基础知识-贝叶斯公式和全概率公式
  • More Effective C++ 条款04:非必要不提供默认构造函数
  • c++string
  • 【计算机网络 | 第8篇】编码与调制
  • 青少年机器人技术(二级)等级考试试卷-实操题(2024年9月)
  • 笔试——Day47
  • 张老师---个人师资介绍
  • python学习DAY49打卡
  • 智慧矿山误报率↓83%!陌讯多模态融合算法在矿用设备监控的落地优化
  • 鸿蒙中CPU活动分析:CPU分析