《SpringBoot启动流程四》:图文带你debug源码分析SpringApplication运行阶段和运行后阶段

简介: 《SpringBoot启动流程四》:图文带你debug源码分析SpringApplication运行阶段和运行后阶段

一、前言

上一篇博文(《SpringBoot启动流程三》:两万+字图文带你debug源码分析SpringApplication准备阶段)我们讨论了Spring应用上下文(ConfigurableApplicationContext)运行前的准备工作。本篇博文,我们把Spring应用上下文启动阶段、和启动后阶段做一个讨论。

注:Spring Boot版本:2.3.7.RELEASE。

二、Spring应用上下文启动阶段

本阶段的执行有refreshContext(ConfigurableApplicationContext)方法实现,具体代码执行流程如下:
在这里插入图片描述
ServletWebServerApplicationContext的类图:
在这里插入图片描述
ServletWebServerApplicationContext间接继承自AbstractApplicationContext,所以最终会进入到AbstractApplicationContext#refresh()方法。

1、AbstractApplicationContext#refresh()方法

走到这里,意味着Spring应用上下文进入Spring生命周期,Spring Boot核心特性随之启动,如:自动装配、嵌入式容器启动Production-Ready特性。
在这里插入图片描述
其中的invokeBeanFactoryPostProcessors()会执行三个BeanFactoryPostProcessor,分别为:SharedMetadataReaderFactoryContextInitializer、ConfigurationWarningsPostProcessor、ConfigFileApplicationListener。
在这里插入图片描述
这其中具体的执行逻辑,博主放在下一篇博文“SpringBoot自动装配原理”中讨论。

三、Spring应用上下文启动后阶段

当Spring应用上下文刷新操作之后,接着执行afterRefresh(ConfigurableApplicationContext,ApplicationArguments)方法,进入ApplicationContext启动后阶段。
在这里插入图片描述
然而,实际上,SpringApplication#afterRefresh(ConfigurableApplicationContext,ApplicationArguments)方法并未给Spring应用上下文启动后阶段提供实现,而是交给开发人员自行扩展,所以这里没有什么讨论的意义。

在执行完完afterRefresh()方法之后,还会执行五步操作:计时监听器停止并统计任务执行信息、输出日志记录执行主类名和时间信息、发布应用上下文已刷新但未运行程序事件ApplicationStartedEvent、执行所有的Runner运行器、发布应用上下文就绪事件ApplicationReadyEvent。

1、计时监听器停止并统计任务执行信息

stopWatch.stop();

在这里插入图片描述
SpringBoot应用的启动时间为:StopWatch.stop()的当前时间 - StopWatch.start()的当前时间,默认统计的任务执行数量为1。

2、输出日志记录执行主类名和时间信息

在这里插入图片描述
这里通过getStartedMessage()方法获取程序启动后需要打印的信息,包括:启动类名称、程序启动需要的时间。

private CharSequence getStartedMessage(StopWatch stopWatch) {
    StringBuilder message = new StringBuilder();
    message.append("Started ");
    appendApplicationName(message);
    message.append(" in ");
    message.append(stopWatch.getTotalTimeMillis() / 1000.0);
    message.append(" seconds");
    try {
        double uptime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0;
        message.append(" (JVM running for ").append(uptime).append(")");
    }
    catch (Throwable ex) {
        // No JVM time available
    }
    return message;
}

Console日志输出如下:
在这里插入图片描述

3、发布Spring应用上下文已刷新但未启动事件

listeners.started(context);

当Spring应用上下文刷新操作完成之后,事件ApplicationStartedEvent被EventPublishingRunListener广播。SpringBoot事件监听器:BackgroundPreinitializer、DelegatingApplicationListener监听到事件,但它们什么都不会做。
在这里插入图片描述
除此之后,还会发布一个AvailabilityChangeEvent事件,状态:ReadinessState.CORRECT,表示应用已处于活动状态。
在这里插入图片描述

4、执行所有的Runner运行器

执行所有的ApplicationRunner和CommandLineRunner 两种运行器,默认情况下是没有运行器的,这里也是留给开发人员自己扩展的。
在这里插入图片描述

5、发布应用上下文就绪事件ApplicationReadyEvent

listeners.running(context);

运行完所有的ApplicationRunner和CommandLineRunner之后,事件ApplicationReadyEvent被EventPublishingRunListener广播。SpringBoot事件监听器:SpringApplicationAdminMXBeanRegister、BackgroundPreinitializer、DelegatingApplicationListener监听到事件。

  1. SpringApplicationAdminMXBeanRegister将自己的状态设置为ready,可以对外提供服务。
  2. BackgroundPreinitializer中调用CountDownLatch.await()等待后台功能的初始化完成。
  3. DelegatingApplicationListener则什么都不做。

在这里插入图片描述
除此之后,还会发布一个AvailabilityChangeEvent事件,状态:ReadinessState.ACCEPTING_TRAFFIC,表示应用可以开始准备接收请求了。
在这里插入图片描述

四、Spring启动流程完结

至此,Spring Boot的启动流程全部总结完毕,下一篇博文以汇总篇的方式,将SpringBoot启动流程文章整合到一起。

后续会出一些博文,比如:SpringBoot如何集成远程配置中心、SpringBoot中配置文件是何时加载的、SpringBoot事件和事件监听器在整个SpringBoot启动流程中具体是如何运作的?(具体到每个事件对应的每个事件监听器都做了什么)、SpringBoot自动装配在启动流程中如何体现、SpringBoot如何内嵌Tomcat容器 等等......敬请期待!!!

相关文章
|
5月前
|
Java Spring
Spring boot 运行服务jar外配置配置文件方式总结
Spring boot 运行服务jar外配置配置文件方式总结
974 0
|
4月前
|
Java 应用服务中间件 Spring
为什么SpringBoot的 jar 可以直接运行?
SpringBoot的 jar 可以直接运行的原因
467 2
|
1月前
|
Dubbo Java 应用服务中间件
深入探讨了“dubbo+nacos+springboot3的native打包成功后运行出现异常”的原因及解决方案
本文深入探讨了“dubbo+nacos+springboot3的native打包成功后运行出现异常”的原因及解决方案。通过检查GraalVM版本兼容性、配置反射列表、使用代理类、检查配置文件、禁用不支持的功能、查看日志文件、使用GraalVM诊断工具和调整GraalVM配置等步骤,帮助开发者快速定位并解决问题,确保服务的正常运行。
54 1
|
1月前
|
安全 Java 应用服务中间件
如何将Spring Boot应用程序运行到自定义端口
如何将Spring Boot应用程序运行到自定义端口
50 0
|
2月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
234 2
|
4月前
|
SQL 前端开发 Java
在IDEA中使用Maven将SpringBoot项目打成jar包、同时运行打成的jar包(前后端项目分离)
这篇文章介绍了如何在IntelliJ IDEA中使用Maven将Spring Boot项目打包成可运行的jar包,并提供了运行jar包的方法。同时,还讨论了如何解决jar包冲突问题,并提供了在IDEA中同时启动Vue前端项目和Spring Boot后端项目的步骤。
在IDEA中使用Maven将SpringBoot项目打成jar包、同时运行打成的jar包(前后端项目分离)
|
5月前
|
关系型数据库 MySQL Java
基于SpringBoot+Vue旅游管理系统【源码(完整源码请私聊)+论文+演示视频+包运行成功】
基于SpringBoot+Vue旅游管理系统【源码(完整源码请私聊)+论文+演示视频+包运行成功】
57 0
基于SpringBoot+Vue旅游管理系统【源码(完整源码请私聊)+论文+演示视频+包运行成功】
|
5月前
|
Java 持续交付 Maven
Spring Boot程序的打包与运行:构建高效部署流程
构建高效的Spring Boot部署流程对于保障应用的快速、稳定上线至关重要。通过采用上述策略,您可以确保部署过程的自动化、可靠性和高效性,从而将专注点放在开发上面。无论是通过Maven的生命周期命令进行打包,还是通过容器技术对部署过程进行优化,选择正确的工具与实践是成功实现这一目标的关键。
227 2
|
4月前
|
Dubbo Java Nacos
【实战攻略】破解Dubbo+Nacos+Spring Boot 3 Native打包后运行异常的终极秘籍——从零开始彻底攻克那些让你头疼不已的技术难题!
【8月更文挑战第15天】Nacos作为微服务注册与配置中心受到欢迎,但使用Dubbo+Nacos+Spring Boot 3进行GraalVM native打包后常遇运行异常。本文剖析此问题及其解决策略:确认GraalVM版本兼容性;配置反射列表以支持必要类和方法;采用静态代理替代动态代理;检查并调整配置文件;禁用不支持的功能;利用日志和GraalVM诊断工具定位问题;根据诊断结果调整GraalVM配置。通过系统排查方法,能有效解决此类问题,确保服务稳定运行。
116 0
|
4月前
|
Java Windows Spring
Spring Boot CMD 运行日志输出中文乱码
Spring Boot CMD 运行日志输出中文乱码
117 0