spring boot(2.4.x之前版本)和spring cloud项目中自动装配的监听执行顺序

目录

[扫描 org.springframework.context.ApplicationListener 指定的类](#扫描 org.springframework.context.ApplicationListener 指定的类)

内置的监听

[spring boot 中的监听](#spring boot 中的监听)

[spring boot autoconfigure 中的监听](#spring boot autoconfigure 中的监听)

[spring boot context 中的监听](#spring boot context 中的监听)

将加载的监听进行排序

[spring boot 中的监听](#spring boot 中的监听)

[spring boot context 中的监听](#spring boot context 中的监听)

监听执行

[监听加载到 SpringApplicationRunListeners 中](#监听加载到 SpringApplicationRunListeners 中)

[调用 SpringApplicationRunListeners 的 environmentPrepared() 进行监听调用](#调用 SpringApplicationRunListeners 的 environmentPrepared() 进行监听调用)

总结


在前面的文章基础上

https://blog.csdn.net/zlpzlpzyd/article/details/136065211

spring 相关的项目中的代码一直在变,下面以 spring boot 2.3.12.RELEASE 以及对应的 spring cloud Hoxton.SR12 进行说明。

spring boot 在启动时会通过 SpringFactoriesLoader 加载 classpath 下 META-INF/spring.factories 中的对应的类。

扫描 org.springframework.context.ApplicationListener 指定的类

其中监听对应的接口为 ApplicationListener,对应的监听是其实现类实现对应的功能。

内置的监听

spring boot 中的监听

复制代码
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

除了 ClearCachesApplicationListener 和 LiquibaseServiceLocatorApplicationListener 都实现了 spring 的接口 Ordered。

spring boot autoconfigure 中的监听

复制代码
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

只有一个 BackgroundPreinitializer,通过注解 @Order 指定了顺序。

spring boot context 中的监听

复制代码
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener

都实现了 spring 的接口 Ordered。

将加载的监听进行排序

在 SpringApplication#getSpringFactoriesInstances() 中通过 AnnotationAwareOrderComparator.sort() 进行处理

其中排序逻辑在父类 OrderComparator 中进行实现。

如果当前监听实现了接口 Ordered,则按照对应的编号进行比较,否则直接返回最低优先级,即 Integer.MAX_VALUE。

findOrder() 在子类 AnnotationAwareOrderComparator 中进行重写,用于处理使用注解 @Order 标记的类。

spring boot 中的监听

对应的监听排序如下

复制代码
CloudFoundryVcapEnvironmentPostProcessor
Integer.MIN_VALUE + 10 - 1

ConfigFileApplicationListener
Integer.MIN_VALUE + 10

AnsiOutputApplicationListener
Integer.MIN_VALUE + 10 + 1

LoggingApplicationListener
Integer.MIN_VALUE + 20

ClasspathLoggingApplicationListener
Integer.MIN_VALUE + 20 + 1

DelegatingApplicationListener
0

ParentContextCloserApplicationListener
Integer.MAX_VALUE - 10

FileEncodingApplicationListener
Integer.MAX_VALUE

ClearCachesApplicationListener
Integer.MAX_VALUE

LiquibaseServiceLocatorApplicationListener
Integer.MAX_VALUE

实际执行结果

spring boot context 中的监听

对应的监听排序如下

复制代码
BootstrapApplicationListener
Integer.MIN_VALUE + 5

LoggingSystemShutdownListener
Integer.MIN_VALUE + 5 + 1

RestartListener
0

结合 spring boot 启动后的顺序如下

复制代码
BootstrapApplicationListener
Integer.MIN_VALUE + 5

LoggingSystemShutdownListener
Integer.MIN_VALUE + 5 + 1

CloudFoundryVcapEnvironmentPostProcessor
Integer.MIN_VALUE + 10 - 1

ConfigFileApplicationListener
Integer.MIN_VALUE + 10

AnsiOutputApplicationListener
Integer.MIN_VALUE + 10 + 1

LoggingApplicationListener
Integer.MIN_VALUE + 20

ClasspathLoggingApplicationListener
Integer.MIN_VALUE + 20 + 1

DelegatingApplicationListener
0

RestartListener
0

ParentContextCloserApplicationListener
Integer.MAX_VALUE - 10

FileEncodingApplicationListener
Integer.MAX_VALUE

ClearCachesApplicationListener
Integer.MAX_VALUE

LiquibaseServiceLocatorApplicationListener
Integer.MAX_VALUE

实际执行结果

可以看到,引入 spring cloud 组件后,默认执行 BootstrapApplicationListener 中的逻辑加载 bootstrap 相关的配置。

监听执行

监听加载到 SpringApplicationRunListeners 中

上面的监听先加载到了 SpringApplicationRunListeners,内部通过一个集合存储SpringApplicationRunListener 的实现类 EventPublishingRunListener 进行存储以进行后续处理。

通过 SpringApplication#getRunListeners() 进行加载

通过反射创建,构造器参数中传入当前类 SpringApplication。

将 SpringApplication 中加载的监听添加到接口 ApplicationEventMulticaster 的实现类。

SimpleApplicationEventMulticaster 的父类 AbstractApplicationEventMulticaster 的内部类 DefaultListenerRetriever 的变量 applicationListeners 中。

调用 SpringApplicationRunListeners 的 environmentPrepared() 进行监听调用

调用 SpringApplicationRunListeners#environmentPrepared() 间接调用 SpringApplicationRunListener 的 environmentPrepared(),对应的实现类为 EventPublishingRunListener。

执行 SpringApplication#prepareEnvironment()

调用 SimpleApplicationEventMulticaster 的 multicastEvent()

调用 SpringApplicationRunListener#environmentPrepared()

调用 SimpleApplicationEventMulticaster#multicastEvent(),参数为事件 ApplicationEnvironmentPreparedEvent。

循环遍历监听,看是否支持对应的事件

由于排序靠前的监听中 ConfigFileApplicationListener 中引入了 ApplicationEnvironmentPreparedEvent,所以优先处理。

调用了 ConfigFileApplicationListener#onApplicationEvent() 后,处理步骤如下

判断当前事件是否为 ApplicationEnvironmentPreparedEvent 的实例,符合条件,执行后续处理。

加载 classpath 中 META-INF/spring.factories 中指定的 EnvironmentPostProcessor 的实现类。

加载当前类为到 EnvironmentPostProcessor 中并进行排序,ConfigFileApplicationListener 实现了接口 EnvironmentPostProcessor。

执行 EnvironmentPostProcessor#postProcessEnvironment() 进行配置文件加载。

总结

综合上述表述,如果引入了 BootstrapApplicationListener 则优先加载,但是在源码中发现如下

正好对应了我们平时写的 spring boot 启动类,可知,在启动时,如果引入了 spring cloud 组件,会先创建一个子容器来加载对应的配置,然后传递到父容器中进行参数传递,完成参数加载。

相关推荐
橙淮8 小时前
并发编程(六)
java·jvm
拽着尾巴的鱼儿8 小时前
springboot openfeign 自定义feign 接口重试机制
java·spring boot·后端
白露与泡影8 小时前
2026大厂Java面试题大全!牛客网最新版
java·开发语言
EntyIU9 小时前
JVM内存与GC笔记
java·jvm·笔记
XS03010610 小时前
并发编程 六
java·后端
yaoxin52112310 小时前
419. 现代 Java IO 最佳实践 - 写入文本文件
java·windows·python
雪宫街道10 小时前
synchronized 锁的范围:对象锁、类锁与代码块锁
java·jvm·后端·面试
x***r15110 小时前
linux安装 jdk-8u291-linux-x64.tar.gz 详细步骤(解压配置环境变量)
java
极光代码工作室10 小时前
基于SpringBoot的校园论坛系统
java·springboot·web开发·后端开发
XS03010611 小时前
Spring Bean 作用域 & 生命周期
java·后端·spring