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());
    }
}

其他

  1. 整个发布流程是同步的还是异步的?
    默认同步的。发布方和订阅方共用一个线程。
// 发布
    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
  1. 如何异步消费事件
    给订阅方上增加@Async注解,这样需要每次增加订阅方都增加注解
  2. 如何保证消费顺序
    当一个事件有多个消费者时,如果需要保证消费次序,可以使用注解@Order
  3. MQ和spring event的区别
    MQ更适合于应用级别的解耦,而spring event适用于应用内的解耦,更轻量
    相对MQ而言,spring event在系统故障时,由于数据是存在内存,会发生数据丢失
  4. 适用场景
  • 业务逻辑解耦。例如用户下单成功后,会触发库存减少、订单创建、支付请求等动作
  • 异步执行。适用于一些发布端不需要关心消费端如何处理,或异步线程不需要堵塞主线程的场景。如日志打印
posted @ 2025-11-06 22:28  ldupup  阅读(45)  评论(0)    收藏  举报