Skip to content
章节导航

Spring 中的事件驱动模型

事件驱动是 Spring 框架中实现解耦、异步处理和系统集成的重要模式。它基于观察者模式,允许组件之间通过事件进行通信。

  • 事件源:用于定义和产生事件对象信息,并把事件对象传递出去
  • 监听器:把监听器注册到事件源上,代表对事件源事件对象感兴趣,接收到事件后去处理

事件驱动机制,通过定义和发布事件,将不同组件之间去解耦,使其能够以异步的方式进行通讯。

Spring 事件监听 vs 消息中间件

特性Spring 事件监听消息中间件 (MQ)
通信范围单个 JVM 进程内跨进程、跨服务器、跨网络
可靠性内存级别,进程重启丢失持久化,高可用
性能极高(内存操作)较高(网络IO)
复杂性简单,Spring 原生支持复杂,需要额外组件
扩展性单机扩展性好,分布式需额外设计天生支持分布式
主要用途应用内模块解耦系统间集成、异步处理

Spring 事件 - 内存级可靠性

Spring 事件 - 优点

  • 执行快,无网络延迟
  • 事务集成好(@TransactionalEventListener)

Spring 事件 - 缺点

  • JVM 重启 → 内存事件丢失
  • 监听器异常可能影响发布者
  • 无消息重试机制(除非自己实现)

Spring 事件 - 适合场景

  • 业务逻辑的通知
  • 不需要持久化的操作
  • 事务一致性要求高的场景

消息中间件 - 企业级可靠性

消息中间件 - 优点

  • 消息持久化(磁盘存储)
  • 高可用(集群部署)
  • 消息确认机制(ACK)
  • 死信队列(处理失败消息)
  • 消息重试

消息中间件 - 缺点

  • 网络延迟
  • 配置复杂
  • 需要额外运维

消息中间件 - 适合场景

  • 支付、订单等关键业务
  • 跨系统数据同步
  • 削峰填谷

内部事件监听

Spring 内置事件的监听,通过 @EventListener 注解实现监听; 注解中如果没有指定事件对象,那么,方法的参数就是感兴趣的对象

案例

1、定义线程池

java
/**
 * 事件驱动此线程池配置类
 *
 * @author 朔风
 * @date 2026-01-15 14:33
 */
@EnableAsync
@Configuration
public class EventThreadPoolConfig {
    private static final Logger logger = LoggerFactory.getLogger(EventThreadPoolConfig.class);

    @Bean("eventAsyncTaskExecutor")
    public Executor getAsyncExecutor() {
        int cpuCount = Runtime.getRuntime().availableProcessors();
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(cpuCount * 2);
        taskExecutor.setMaxPoolSize(cpuCount * 4);
        taskExecutor.setQueueCapacity(50_000);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("event-async-");

        // 拒绝策略
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);

        taskExecutor.setAwaitTerminationSeconds(60);
        taskExecutor.initialize();
        return taskExecutor;
    }

}

2、定义事件

java
/**
 * 推送事件
 *
 * @author 朔风
 * @date 2026-01-15 14:14
 */
public class PushEvent extends ApplicationEvent {

    public PushEvent(Object source) {
        super(source);
    }

}

3、推送事件消息定义

java
/**
 * 推送事件消息定义
 *
 * @author 朔风
 * @date 2026-01-15 14:16
 */
public class PushEventMessage {

    private Long userId;
    private Long pushTime;
    private String content;

    public PushEventMessage(Long userId, Long pushTime, String content) {
        this.userId = userId;
        this.pushTime = pushTime;
        this.content = content;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Long getPushTime() {
        return pushTime;
    }

    public void setPushTime(Long pushTime) {
        this.pushTime = pushTime;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "PushEventMessage{" +
                "userId=" + userId +
                ", pushTime=" + pushTime +
                ", content='" + content + '\'' +
                '}';
    }

}

4、定义监听者

推送事件监听,通过实现 ApplicationListener 接口实现对事件的监听

java
/**
 * 推送事件监听
 * 通过实现 ApplicationListener 接口实现对事件的监听
 *
 * @author 朔风
 * @date 2026-01-15 14:19
 */
@Component
public class PushEventListener01 implements ApplicationListener<PushEvent> {
    private static final Logger logger = LoggerFactory.getLogger(PushEventListener01.class);

    @Async("eventAsyncTaskExecutor")
    @Override
    public void onApplicationEvent(PushEvent event) {
        PushEventMessage message = (PushEventMessage) event.getSource();
        logger.info("PushEventListener01 {}.....", message.toString());
    }

}

推送事件监听,注解驱动

java
/**
 * 推送事件监听,注解驱动
 *
 * @author 朔风
 * @date 2026-01-15 14:22
 */
 @Component
public class PushEventListener02 {
    private static final Logger logger = LoggerFactory.getLogger(PushEventListener02.class);

    @Async("eventAsyncTaskExecutor")
    @EventListener(PushEvent.class)
    public void receive(PushEvent event) {
        PushEventMessage message = (PushEventMessage) event.getSource();
        logger.info("PushEventListener02 {} .....", message.toString());
    }
    
}

5、推送事件发布

java
/**
 * 推送事件发布
 *
 * @author 朔风
 * @date 2026-01-15 14:28
 */
@Component
public class PushEventPublisher {

    /* ApplicationContext 继承于 ApplicationEventPublisher */
    private final ApplicationContext applicationContext;
    private final ApplicationEventPublisher publisher;

    public PushEventPublisher(ApplicationContext applicationContext, ApplicationEventPublisher publisher) {
        this.applicationContext = applicationContext;
        this.publisher = publisher;
    }

    /***
     * 事件发布
     *
     * @author 朔风
     * @date 2026/1/15 14:29
     * @param message message
     * @return void
     */
    public void publish(PushEventMessage message) {
        /* 第一种方式 */
        applicationContext.publishEvent(new PushEvent(message));
        /* 第二种方式 */
        publisher.publishEvent(new PushEvent(message));
    }

}