Spring ApplicationEventPublisher 事件发布
ApplicationEventPublisher
ApplicationEventPublisher是一个事件发布器,我们可以通过ApplicationContext来发布一个相应的事件
主要涉及到 事件定义、事件发布、事件订阅 三个模块
demo
事件
需要继承org.springframework.context.ApplicationEvent
/**
* 定义我的事件
*/
public class MyEvent extends ApplicationEvent {
private String msg;
public MyEvent(String msg) {
super(msg);
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
发布
使用applicationEventPublisher发布事件即可
/**
* 发布方
*
* @author
* @since 2024/12/4 20:30
*/
@Component
public class MyPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
private int id = 0;
/**
* 起了个定时任务,用来测试事件发布
*/
@Scheduled(cron = "*/30 * * * * ?")
public void loop() {
publish();
}
public void publish() {
System.out.println("publish event. id: " + id);
applicationEventPublisher.publishEvent(new MyEvent("new event " + id + " at " + System.currentTimeMillis()));
id++;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}
订阅
实现org.springframework.context.ApplicationListener,注入到spring容器中。在泛型中指定需要监听的事件类型
/**
* 订阅方
*/
@Component
public class MyListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("receive a event. msg : " + event.getMsg());
}
}
测试结果:
publish event. id: 0
receive a event. msg : new event 0 at 1733368770009
publish event. id: 1
receive a event. msg : new event 1 at 1733368800008
publish event. id: 2
receive a event. msg : new event 2 at 1733368830011
publish event. id: 3
receive a event. msg : new event 3 at 1733368860007
其他事件监听方式
使用注解@EventListener
@Component
public class MyListener2 {
@EventListener
public void onApplicationEvent(MyEvent event) {
System.out.println("receive a event. msg : " + event.getMsg());
}
}
其他
- 整个发布流程是同步的还是异步的?
默认同步的。发布方和订阅方共用一个线程。
// 发布
public void publish() {
id++;
System.out.printf("publish event start. id: %s. threadName: %s %n", id, Thread.currentThread().getName());
applicationEventPublisher.publishEvent(new MyEvent("new event " + id + " at " + System.currentTimeMillis()));
System.out.printf("publish event start. id: %s. threadName: %s %n", id, Thread.currentThread().getName());
}
// 订阅
@EventListener
public void onApplicationEvent(MyEvent event) throws InterruptedException {
sleep(5000);
System.out.printf("receive a event. msg : %s. threadName: %s %n", event.getMsg(), Thread.currentThread().getName());
}
// 测试结果
// publish event start. id: 1. threadName: scheduled-task-thread2
// receive a event. msg : new event 1 at 1733369970012. threadName: scheduled-task-thread2
// publish event start. id: 1. threadName: scheduled-task-thread2
- 如何异步消费事件
给订阅方上增加@Async注解,这样需要每次增加订阅方都增加注解 - 如何保证消费顺序
当一个事件有多个消费者时,如果需要保证消费次序,可以使用注解@Order - MQ和spring event的区别
MQ更适合于应用级别的解耦,而spring event适用于应用内的解耦,更轻量
相对MQ而言,spring event在系统故障时,由于数据是存在内存,会发生数据丢失 - 适用场景
- 业务逻辑解耦。例如用户下单成功后,会触发库存减少、订单创建、支付请求等动作
- 异步执行。适用于一些发布端不需要关心消费端如何处理,或异步线程不需要堵塞主线程的场景。如日志打印

浙公网安备 33010602011771号