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

网友投稿 1557 2022-09-30

《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监听到事件。

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

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

四、Spring启动流程完结

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

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:小程序怎么生成二维码(小程序怎么生成二维码图片)
下一篇:jupyter修改默认“文件存储路径”,其实没必要,使用这种方法,随时随地可修改
相关文章

 发表评论

暂时没有评论,来抢沙发吧~