Spring Boot / Spring Framework 事件大全
适用范围:Spring Boot、Spring Framework、Spring MVC、Spring Security、事务事件以及自定义业务事件。
本文重点说明:事件是什么、什么时候触发、如何监听、如何使用 Spring 提供的机制、实际应用场景以及注意事项。
1. Spring 事件机制概览
Spring 的事件模型可以概括为:
text
事件发布者
│
▼
ApplicationEventPublisher
│
▼
Spring ApplicationEventMulticaster
│
├──────────────┬──────────────┐
▼ ▼ ▼
Listener Listener Listener
│ │ │
▼ ▼ ▼
业务处理 日志/监控 第三方调用
Spring 提供的核心接口/注解:
ApplicationEventApplicationEventPublisherApplicationListener@EventListener@TransactionalEventListener@Async
最常见的业务事件模式:
java
publisher.publishEvent(new UserRegisteredEvent(userId));
监听:
java
@EventListener
public void handle(UserRegisteredEvent event) {
// 处理事件
}
2. Spring Boot 启动事件完整生命周期
执行:
java
SpringApplication.run(Application.class, args);
典型启动顺序可以理解为:
text
SpringApplication.run()
│
▼
ApplicationStartingEvent
│
▼
ApplicationEnvironmentPreparedEvent
│
▼
ApplicationContextInitializedEvent
│
▼
ApplicationPreparedEvent
│
▼
ApplicationContext.refresh()
│
▼
ContextRefreshedEvent
│
▼
ApplicationStartedEvent
│
▼
AvailabilityChangeEvent
LivenessState.CORRECT
│
▼
ApplicationRunner
CommandLineRunner
│
▼
ApplicationReadyEvent
│
▼
AvailabilityChangeEvent
ReadinessState.ACCEPTING_TRAFFIC
│
▼
应用正式接收流量
如果启动过程中发生异常:
text
ApplicationFailedEvent
3. Spring Boot 启动生命周期事件
3.1 ApplicationStartingEvent
触发时机
Spring Boot 启动最早阶段。
java
SpringApplication.run(Application.class, args);
开始执行后,很早就会发布该事件。
此时通常:
text
Environment 尚未完全准备
ApplicationContext 尚未创建
Bean 尚未创建
监听
由于该事件发生得很早,普通 @Component 监听器可能来不及注册。
可以通过:
java
SpringApplication application =
new SpringApplication(Application.class);
application.addListeners(
new MyApplicationStartingListener()
);
application.run(args);
监听器:
java
public class MyApplicationStartingListener
implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(
ApplicationStartingEvent event) {
System.out.println("Spring Boot 开始启动");
}
}
适用场景
- 最早期启动日志
- 启动监控
- 启动时间统计
- 初始化非常底层的组件
3.2 ApplicationEnvironmentPreparedEvent
触发时机
Environment 已经准备完成,但 ApplicationContext 尚未创建。
text
ApplicationStartingEvent
↓
准备 Environment
↓
ApplicationEnvironmentPreparedEvent
↓
创建 ApplicationContext
可以获取
java
Environment environment =
event.getEnvironment();
例如:
java
@Component
public class EnvironmentListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override
public void onApplicationEvent(
ApplicationEnvironmentPreparedEvent event) {
Environment environment = event.getEnvironment();
String profile =
environment.getProperty(
"spring.profiles.active"
);
System.out.println("当前 Profile:" + profile);
}
}
适用场景
- 读取启动环境
- 根据 Profile 做早期处理
- 读取启动参数
- 环境初始化
3.3 ApplicationContextInitializedEvent
触发时机
ApplicationContext 已经创建,并且 ApplicationContextInitializer 已执行。
但 Bean Definition 尚未全部加载。
text
ApplicationContext 已创建
Environment 已准备
BeanDefinition 尚未加载
Bean 尚未创建
示例
java
@Component
public class ContextInitializedListener {
@EventListener
public void handle(ApplicationContextInitializedEvent event) {
System.out.println(
"ApplicationContext 初始化完成"
);
}
}
适用场景
- Context 初始化阶段监控
- 早期容器扩展
- 配合
ApplicationContextInitializer
3.4 ApplicationPreparedEvent
触发时机
ApplicationContext 已经准备完成,Bean Definition 已加载,但 Context 尚未完成 refresh()。
text
ApplicationContextInitializedEvent
↓
加载 Bean Definition
↓
ApplicationPreparedEvent
↓
refresh()
状态
text
Environment ✅
ApplicationContext ✅
BeanDefinition ✅
Bean 实例 ❌ / 尚未完成
Context.refresh() ❌
示例
java
@Component
public class PreparedListener {
@EventListener
public void handle(ApplicationPreparedEvent event) {
System.out.println(
"ApplicationContext 已准备完成"
);
}
}
4. Spring Framework Context 生命周期事件
这些事件不是 Spring Boot 独有,而是 Spring Framework 提供的核心事件。
4.1 ContextRefreshedEvent
触发时机
当:
java
ApplicationContext.refresh();
完成后触发。
意义
可以理解为:
text
BeanDefinition 加载
↓
Bean 创建
↓
依赖注入
↓
BeanPostProcessor
↓
Context 刷新完成
↓
ContextRefreshedEvent
示例
java
@Component
public class ContextRefreshListener {
@EventListener
public void handle(ContextRefreshedEvent event) {
System.out.println(
"Spring Context 刷新完成"
);
}
}
常见用途
- 初始化缓存
- 初始化字典
- 容器初始化完成后的操作
- 启动内部组件
如果是 Spring Boot 应用,通常优先考虑
ApplicationReadyEvent,因为它更明确地表示整个 Boot 应用已经准备完成。
4.2 ContextStartedEvent
触发方式
当:
java
applicationContext.start();
被调用时触发。
示例
java
@EventListener
public void handle(ContextStartedEvent event) {
System.out.println("Spring Context Started");
}
注意
Spring Boot Web 应用中实际使用频率较低。
4.3 ContextStoppedEvent
触发方式
当:
java
applicationContext.stop();
执行时触发。
示例
java
@EventListener
public void handle(ContextStoppedEvent event) {
System.out.println("Spring Context Stopped");
}
4.4 ContextClosedEvent
触发时机
ApplicationContext 关闭时触发。
例如:
java
applicationContext.close();
Spring Boot 应用正常停止时,也会经历 Context 关闭过程。
示例
java
@Component
public class ShutdownListener {
@EventListener
public void handle(ContextClosedEvent event) {
System.out.println(
"Spring Context 正在关闭"
);
}
}
常见用途
- 停止后台线程
- 关闭自定义资源
- 清理临时资源
- 保存运行状态
- 停止第三方客户端
如果资源本身是 Spring Bean 管理的,更推荐优先考虑:
java
@PreDestroy
public void destroy() {
// 释放资源
}
5. ApplicationStartedEvent
5.1 触发时机
Context refresh 完成以后触发:
text
ContextRefreshedEvent
↓
ApplicationStartedEvent
↓
ApplicationRunner
CommandLineRunner
也就是说:
Spring Boot 已经启动,但
ApplicationRunner和CommandLineRunner尚未执行。
5.2 示例
java
@Component
public class StartedListener {
@EventListener(ApplicationStartedEvent.class)
public void handle(ApplicationStartedEvent event) {
System.out.println(
"Spring Boot 已启动"
);
}
}
5.3 适用场景
- 启动阶段监控
- 启动时间统计
- 在 Runner 之前执行一些逻辑
- 判断 Spring Context 是否已经启动
6. AvailabilityChangeEvent
Spring Boot 提供应用可用性事件。
主要涉及:
java
LivenessState
ReadinessState
6.1 LivenessState
表示:
应用是否还活着。
正常状态:
java
LivenessState.CORRECT
6.2 ReadinessState
表示:
应用是否已经准备好接收流量。
正常状态:
java
ReadinessState.ACCEPTING_TRAFFIC
6.3 启动过程
可以理解为:
text
ApplicationStartedEvent
↓
LivenessState.CORRECT
↓
ApplicationRunner
CommandLineRunner
↓
ApplicationReadyEvent
↓
ReadinessState.ACCEPTING_TRAFFIC
Kubernetes 场景
特别适合:
text
Spring Boot
↓
Docker
↓
Kubernetes
↓
Liveness / Readiness Probe
例如:
text
Liveness = CORRECT
↓
容器仍然健康
Readiness = ACCEPTING_TRAFFIC
↓
可以接收请求
7. ApplicationReadyEvent
这是 Spring Boot 项目中最常用的启动完成事件之一。
7.1 触发时机
text
ApplicationStartedEvent
↓
ApplicationRunner
CommandLineRunner
↓
ApplicationReadyEvent
它表示:
Spring Boot 应用已经尽可能完整地启动,可以正常提供服务。
7.2 推荐写法
java
@Component
public class ApplicationReadyListener {
@EventListener(ApplicationReadyEvent.class)
public void handle(ApplicationReadyEvent event) {
System.out.println(
"========== 应用启动完成 =========="
);
}
}
也可以:
java
@EventListener
public void handle(ApplicationReadyEvent event) {
// 初始化缓存
// 加载字典
// 初始化业务数据
}
7.3 适用场景
- 初始化业务缓存
- 加载基础数据
- 启动业务定时任务
- 启动第三方连接
- 启动完成通知
- 上报服务启动状态
注意
如果这里执行非常耗时的任务,可能会影响应用进入 Ready 状态。
如果任务很重,可以考虑:
java
@Async
@EventListener(ApplicationReadyEvent.class)
public void handle(ApplicationReadyEvent event) {
// 异步初始化
}
但异步初始化要考虑并发安全,以及业务接口是否可能在初始化完成前被调用。
8. ApplicationFailedEvent
8.1 触发时机
Spring Boot 启动过程中发生异常,并导致启动失败时触发。
text
SpringApplication.run()
↓
启动
↓
发生异常
↓
ApplicationFailedEvent
8.2 示例
java
public class FailedListener
implements ApplicationListener<ApplicationFailedEvent> {
@Override
public void onApplicationEvent(
ApplicationFailedEvent event) {
Throwable exception =
event.getException();
System.err.println(
"Spring Boot 启动失败:" +
exception.getMessage()
);
}
}
由于该事件也可能发生在 ApplicationContext 创建完成之前,所以如果需要覆盖非常早期的启动失败,需要考虑通过 SpringApplication.addListeners() 注册。
8.3 适用场景
- 启动失败日志
- 告警
- 钉钉/企业微信通知
- 记录启动失败原因
- 启动监控
9. RequestHandledEvent
这是 Spring Web 相关事件。
请求处理完成以后,可以产生请求处理事件。
示例
java
@Component
public class RequestListener {
@EventListener
public void handle(RequestHandledEvent event) {
System.out.println(
"请求处理完成"
);
}
}
可用于
- 请求监控
- 请求统计
- 请求耗时分析
- 异常统计
不过现代 Spring Boot 项目中,如果已经使用:
- Spring Boot Actuator
- Micrometer
- Prometheus
- OpenTelemetry
通常不建议单纯依赖 RequestHandledEvent 做完整的 Web 可观测性。
10. ServletRequestHandledEvent
对于 Servlet Web 应用,可以使用:
java
ServletRequestHandledEvent
它是 Web 请求处理相关事件。
典型使用:
java
@EventListener
public void handle(
ServletRequestHandledEvent event) {
System.out.println(
"URL:" + event.getRequestUrl()
);
System.out.println(
"耗时:" + event.getProcessingTimeMillis()
);
}
适合简单的请求统计和监控。
11. Spring Security 事件
如果项目使用 Spring Security,还会产生大量安全相关事件。
常见事件包括:
| 事件 | 含义 |
|---|---|
AuthenticationSuccessEvent |
认证成功 |
AbstractAuthenticationFailureEvent |
认证失败 |
AuthenticationFailureBadCredentialsEvent |
用户名/密码错误 |
AuthorizationDeniedEvent |
授权被拒绝 |
11.1 登录成功
java
@Component
public class LoginSuccessListener {
@EventListener
public void handle(AuthenticationSuccessEvent event) {
System.out.println(
"用户认证成功:" +
event.getAuthentication().getName()
);
}
}
11.2 登录失败
java
@Component
public class LoginFailureListener {
@EventListener
public void handle(
AuthenticationFailureBadCredentialsEvent event) {
System.out.println(
"登录失败:" +
event.getAuthentication().getName()
);
}
}
常见用途
text
登录成功
↓
记录登录日志
登录失败
↓
失败次数统计
↓
安全告警
授权失败
↓
越权监控
12. Spring 事务事件
这是企业项目中非常重要的一类。
核心注解:
java
@TransactionalEventListener
普通:
java
@EventListener
与事务事件的核心区别:
text
@EventListener
↓
事件发布后即可处理
@TransactionalEventListener
↓
根据事务阶段处理
13. TransactionPhase
常见阶段:
java
TransactionPhase.BEFORE_COMMIT
TransactionPhase.AFTER_COMMIT
TransactionPhase.AFTER_ROLLBACK
TransactionPhase.AFTER_COMPLETION
13.1 BEFORE_COMMIT
事务提交之前执行:
java
@TransactionalEventListener(
phase = TransactionPhase.BEFORE_COMMIT
)
public void handle(UserRegisteredEvent event) {
}
13.2 AFTER_COMMIT
事务提交成功以后执行。
这是非常常见的模式:
java
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT
)
public void handle(UserRegisteredEvent event) {
// 事务提交成功后执行
}
适合:
- 发送消息
- 调用第三方接口
- 发送通知
- 更新非核心数据
- 发布下游业务事件
13.3 AFTER_ROLLBACK
事务回滚后执行:
java
@TransactionalEventListener(
phase = TransactionPhase.AFTER_ROLLBACK
)
public void handle(UserRegisteredEvent event) {
// 事务回滚后的处理
}
13.4 AFTER_COMPLETION
事务完成后执行,不论提交还是回滚:
java
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMPLETION
)
public void handle(UserRegisteredEvent event) {
}
14. 自定义业务事件
这是 Spring 事件机制最重要的实际应用。
例如用户注册:
text
UserService
│
▼
保存用户
│
▼
UserRegisteredEvent
│
├──────────────► EmailListener
│
├──────────────► CouponListener
│
└──────────────► LogListener
15. 定义业务事件
现代 Spring 项目可以直接使用 Java record:
java
public record UserRegisteredEvent(
Long userId
) {
}
也可以继承 ApplicationEvent,但现代 Spring 的业务事件通常不要求必须继承 ApplicationEvent。
16. 发布业务事件
Spring 提供:
java
ApplicationEventPublisher
例如:
java
@Service
public class UserService {
private final ApplicationEventPublisher publisher;
public UserService(
ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Transactional
public void register(Long userId) {
// 1. 保存用户
// userRepository.save(...);
// 2. 发布事件
publisher.publishEvent(
new UserRegisteredEvent(userId)
);
}
}
17. 监听业务事件
java
@Component
public class UserRegisteredListener {
@EventListener
public void handle(
UserRegisteredEvent event) {
System.out.println(
"用户注册:" +
event.userId()
);
}
}
18. 一个事件可以有多个监听器
例如:
邮件
java
@Component
public class EmailListener {
@EventListener
public void handle(
UserRegisteredEvent event) {
// 发送欢迎邮件
}
}
优惠券
java
@Component
public class CouponListener {
@EventListener
public void handle(
UserRegisteredEvent event) {
// 发放优惠券
}
}
日志
java
@Component
public class LogListener {
@EventListener
public void handle(
UserRegisteredEvent event) {
// 记录用户注册日志
}
}
于是:
text
用户注册
│
▼
UserRegisteredEvent
│
├── EmailListener
├── CouponListener
└── LogListener
业务核心代码不需要关心这些附加逻辑。
19. @Order 控制多个监听器顺序
如果多个监听器需要明确执行顺序:
java
@Component
public class FirstListener {
@Order(1)
@EventListener
public void handle(UserRegisteredEvent event) {
}
}
java
@Component
public class SecondListener {
@Order(2)
@EventListener
public void handle(UserRegisteredEvent event) {
}
}
执行:
text
FirstListener
↓
SecondListener
注意
不要过度依赖事件监听器顺序设计复杂业务事务关系。
如果顺序本身是业务规则,通常应该在明确的业务服务中表达,而不是隐藏在多个 Listener 中。
20. 异步事件
默认的 Spring 事件监听通常是同步调用。
例如:
java
@EventListener
public void handle(UserRegisteredEvent event) {
// 耗时操作
}
发布事件的线程可能需要等待监听器执行。
如果希望异步:
java
@EnableAsync
@SpringBootApplication
public class Application {
}
监听器:
java
@Async
@EventListener
public void handle(UserRegisteredEvent event) {
// 异步执行
}
结构:
text
主线程
│
├── 保存用户
│
├── publishEvent()
│
└── 继续执行
│
▼
线程池
│
▼
Listener
21. 事务 + 异步事件
企业项目非常常见:
java
@Async
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT
)
public void handle(UserRegisteredEvent event) {
// 事务提交成功后
// 异步发送邮件
}
推荐场景:
text
数据库事务
│
▼
用户注册
│
▼
事务 COMMIT
│
▼
UserRegisteredEvent
│
▼
线程池
│
├── 邮件
├── 短信
└── 第三方 API
22. Spring 事件 vs MQ
Spring 事件非常方便,但不要把它当成消息队列。
| 对比 | Spring Event | RabbitMQ/Kafka 等 MQ |
|---|---|---|
| 是否进程内 | 是 | 通常否 |
| 是否持久化 | 默认否 | 可以 |
| 服务重启后事件 | 默认丢失 | 可持久化 |
| 跨服务 | 不适合 | 适合 |
| 性能 | 高 | 高 |
| 使用复杂度 | 低 | 较高 |
| 典型场景 | 单体/同 JVM 解耦 | 微服务通信 |
| 可靠消息 | 不适合 | 适合 |
| 事务最终一致性 | 需要额外设计 | 更适合 |
简单原则:
text
同一个 Spring Boot 应用内部解耦
↓
Spring Event
跨服务通信
↓
MQ
必须保证消息不丢
↓
MQ + 持久化/可靠投递机制
23. Spring Event 最容易踩的坑
23.1 事件默认不是 MQ
java
publisher.publishEvent(event);
并不意味着:
text
事件永久保存
应用进程挂掉,事件不会自动恢复。
23.2 @EventListener 默认不是事务消息
例如:
java
@Transactional
public void createOrder() {
saveOrder();
publisher.publishEvent(
new OrderCreatedEvent(orderId)
);
}
普通:
java
@EventListener
监听器可能在数据库事务真正提交前执行。
如果你需要:
数据库提交成功以后再处理
应该考虑:
java
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT
)
23.3 AFTER_COMMIT 中再次操作数据库要谨慎
事务已经提交。
如果监听器中需要开启新的数据库事务,可以明确使用:
java
@Transactional(propagation = Propagation.REQUIRES_NEW)
具体是否需要,要根据业务设计决定。
23.4 @Async 会改变异常处理方式
同步:
java
@EventListener
异常可以直接影响调用链。
异步:
java
@Async
@EventListener
异常已经发生在线程池线程中,需要单独设计异常处理、重试和监控。
24. Spring Boot 事件推荐使用场景
| 需求 | 推荐机制 |
|---|---|
| 应用启动完成 | ApplicationReadyEvent |
| 应用启动失败 | ApplicationFailedEvent |
| Context 刷新完成 | ContextRefreshedEvent |
| 应用关闭 | ContextClosedEvent |
| Runner 前启动通知 | ApplicationStartedEvent |
| Kubernetes 存活状态 | AvailabilityChangeEvent |
| Kubernetes 就绪状态 | AvailabilityChangeEvent |
| 用户注册后执行附加逻辑 | 自定义 Event |
| 订单创建后执行附加逻辑 | 自定义 Event |
| 事务提交成功后执行 | @TransactionalEventListener(AFTER_COMMIT) |
| 事务回滚后执行 | AFTER_ROLLBACK |
| 异步事件 | @Async + @EventListener |
| 跨微服务 | MQ,不建议 Spring Event |
| 可靠消息 | MQ + 持久化机制 |
25. 最推荐的企业项目事件架构
建议按照下面的方式设计:
text
Spring Boot
│
┌──────────────┼──────────────┐
│ │ │
启动事件 容器事件 关闭事件
│ │ │
ApplicationReady ContextRefresh ContextClosed
│
▼
业务系统
│
├── UserRegisteredEvent
├── OrderCreatedEvent
├── PaymentSuccessEvent
├── FileUploadedEvent
└── MessageSentEvent
│
▼
ApplicationEventPublisher
│
┌───────────┼───────────┐
▼ ▼ ▼
Listener Listener Listener
│ │ │
邮件 短信 日志
26. 一个完整可复制的模板
26.1 定义事件
java
public record UserRegisteredEvent(
Long userId
) {
}
26.2 发布事件
java
@Service
public class UserService {
private final ApplicationEventPublisher publisher;
public UserService(
ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Transactional
public void register(Long userId) {
// 保存用户
// userRepository.save(...);
publisher.publishEvent(
new UserRegisteredEvent(userId)
);
}
}
26.3 事务提交后处理
java
@Component
public class UserRegisteredListener {
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT
)
public void handle(
UserRegisteredEvent event) {
System.out.println(
"用户注册成功:" +
event.userId()
);
}
}
26.4 异步处理
java
@Component
public class UserRegisteredAsyncListener {
@Async
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT
)
public void handle(
UserRegisteredEvent event) {
// 发邮件
// 发短信
// 推送
// 调用第三方接口
}
}
26.5 启用异步
java
@Configuration
@EnableAsync
public class AsyncConfig {
}
26.6 应用启动完成
java
@Component
public class StartupListener {
@EventListener(ApplicationReadyEvent.class)
public void ready(ApplicationReadyEvent event) {
System.out.println(
"系统启动完成"
);
}
}
26.7 应用关闭
java
@Component
public class ShutdownListener {
@EventListener
public void closed(ContextClosedEvent event) {
System.out.println(
"系统正在关闭"
);
}
}
27. 事件选择速查表
text
我要监听 Spring Boot 启动完成
↓
ApplicationReadyEvent
我要监听 Spring Boot 启动失败
↓
ApplicationFailedEvent
我要监听 Context 刷新完成
↓
ContextRefreshedEvent
我要监听 Spring 容器关闭
↓
ContextClosedEvent
我要监听 Kubernetes 就绪状态
↓
AvailabilityChangeEvent
我要在业务代码中发布事件
↓
ApplicationEventPublisher
我要监听业务事件
↓
@EventListener
我要等事务提交成功后再处理
↓
@TransactionalEventListener
AFTER_COMMIT
我要在事务回滚后处理
↓
@TransactionalEventListener
AFTER_ROLLBACK
我要异步处理事件
↓
@Async + @EventListener
我要跨服务传递事件
↓
MQ
我要可靠消息
↓
MQ + 持久化/重试/幂等等机制
28. 核心结论
Spring 事件可以分成三层:
第一层:Spring Boot 生命周期事件
text
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationReadyEvent
ApplicationFailedEvent
AvailabilityChangeEvent
第二层:Spring Framework 容器/Web 事件
text
ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
RequestHandledEvent
ServletRequestHandledEvent
第三层:业务事件
text
UserRegisteredEvent
OrderCreatedEvent
PaymentSuccessEvent
FileUploadedEvent
...
其中企业项目最值得掌握的是:
text
ApplicationReadyEvent
ContextClosedEvent
ApplicationEventPublisher
@EventListener
@TransactionalEventListener
@Async
以及一个非常重要的架构原则:
text
Spring Event
↓
适合 JVM / Spring Boot 进程内部解耦
MQ
↓
适合跨服务、可靠消息、持久化消息
官方参考
- Spring Framework Events:https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html
- Spring Boot Application Events:https://docs.spring.io/spring-boot/reference/features/spring-application.html
- Spring Boot Application Events API:https://docs.spring.io/spring-boot/api/java/org/springframework/boot/context/event/package-summary.html
- Spring Transaction-bound Events:https://docs.spring.io/spring-framework/reference/data-access/transaction/event.html
- Spring ApplicationEventPublisher:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationEventPublisher.html