Spring 事件机制
Spring 事件机制
为什么要有事件机制?
在一个系统中,不同模块经常需要“感知”某些行为发生,比如:
- 用户注册成功后,发送欢迎邮件
- 订单创建后,通知库存服务
- Spring 容器刷新完毕后,执行一些初始化逻辑
我们不希望模块之间直接耦合调用。
Spring 提供了内置的 事件发布/监听模型 来优雅解决这个问题。
事件模型的三要素
组件 | 作用 | 常见实现类 |
---|---|---|
事件(ApplicationEvent) | 封装消息数据 | 自定义事件类 |
事件发布器(ApplicationEventPublisher) | 负责发布事件 | ApplicationContext 本身 |
事件监听器(ApplicationListener) | 监听并处理事件 | 自定义监听类 |
核心类结构
flowchart TD
A[ApplicationEventPublisher] -->|publishEvent| B[ApplicationEventMulticaster]
B -->|for each listener| C[ApplicationListener]
C -->|onApplicationEvent| D[处理业务逻辑]
ApplicationContext 既是 Bean 工厂,也是事件发布器,它内部维护了一个事件广播器(ApplicationEventMulticaster)。
自定义事件 Demo
1️⃣ 定义事件
1 | public class UserRegisterEvent extends ApplicationEvent { |
2️⃣ 定义监听器
1 |
|
3️⃣ 发布事件
1 |
|
4️⃣ 测试运行
1 |
|
运行结果:
1 | 用户注册成功:ryan |
Spring 事件源码流程
当你调用:
1 | publisher.publishEvent(event); |
实际调用的是:
1 | AbstractApplicationContext#publishEvent() |
源码简化:
1 | public void publishEvent(ApplicationEvent event) { |
然后:
1 | SimpleApplicationEventMulticaster#multicastEvent() |
1 | for (ApplicationListener<?> listener : getApplicationListeners(event)) { |
📌 核心逻辑:
- 拿到所有监听当前事件的监听器
- 挨个执行
onApplicationEvent()
如果容器里配置了异步执行器(Executor),还可以异步广播事件。
同步 vs 异步事件
默认情况下事件是同步广播的:
- 发布者会等待所有监听器处理完事件后才继续执行
如果想让监听器异步执行:1
2
3
4
5
6
7
8
9
public class WelcomeEmailListener implements ApplicationListener<UserRegisterEvent> {
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("异步发送邮件:" + event.getUsername());
}
}
调试建议
- 在
AbstractApplicationContext#publishEvent()
打断点 - 进入
SimpleApplicationEventMulticaster#multicastEvent()
- 查看容器里有哪些监听器被选中执行
- 如果想看容器内置事件,可在容器启动时观察:
ContextRefreshedEvent
ContextClosedEvent
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.