在 Spring 生态中,Spring Event(Spring 事件机制)是实现组件间解耦的核心技术之一,它基于观察者设计模式,提供了一套完整的事件发布 - 订阅机制,广泛应用于业务解耦、异步通知、系统监控等场景。本文将从技术原理、核心组件、使用方法到高级特性,全方位拆解 Spring Event,帮助你快速掌握并落地到实际项目中。
一、Spring Event 技术原理浅解
1. 核心设计思想
Spring Event 遵循观察者模式(发布者 - 订阅者模式),将事件的产生(发布者)与事件的处理(订阅者)解耦,发布者无需知晓订阅者的存在,订阅者也无需关注事件的来源,两者通过 Spring 容器完成事件的传递,实现 "发布者只管发,订阅者只管接" 的解耦效果。
2. 核心组件
Spring Event 的运行依赖 4 个核心组件,它们协同工作完成事件的传播与处理:
| 组件名称 | 作用说明 |
|---|---|
| ApplicationEvent | 事件载体:封装事件相关数据,所有自定义事件需继承该类(Spring 4.2 + 支持任意普通类作为事件) |
| ApplicationEventPublisher | 事件发布者:负责发布事件,通常由 Spring 容器自动注入(ApplicationContext实现了该接口) |
| ApplicationListener/@EventListener | 事件订阅者:负责监听并处理事件,前者是接口形式,后者是注解形式(推荐) |
| ApplicationEventMulticaster | 事件广播器:核心中间件,负责将发布者的事件分发给所有对应的订阅者,默认实现为SimpleApplicationEventMulticaster |
3. 事件传播流程
Spring Event 的完整执行流程如下:
事件发布:业务代码通过ApplicationEventPublisher.publishEvent()发布事件(可传入自定义事件对象或普通 POJO);
事件接收: 事件广播器ApplicationEventMulticaster接收发布的事件,负责筛选对应的订阅者;
事件分发: 广播器根据事件类型,将事件分发给所有匹配的监听器(同步 / 异步分发,默认同步);
事件处理: 监听器接收到事件后,执行自定义的业务处理逻辑;
完成回调: 所有监听器处理完毕后,事件传播流程结束(异步场景下无统一回调)。
事件发布流程中,有三个核心概念,它们之间的关系如下图:

- 事件源(ApplicationEvent): 这个就是你要发布的事件对象。
- 事件发布器(ApplicationEventPublisher): 这是事件的发布工具。
- 事件监听器(ApplicationListener): 这个相当于是事件的消费者。
4. 关键特性
- 解耦性: 发布者与订阅者无直接依赖,降低代码耦合度,便于维护和扩展;
- 灵活性: 支持同步 / 异步处理、事件过滤、有序监听,满足不同业务场景需求;
- 集成性: 与 Spring 容器深度集成,支持事务绑定、依赖注入等 Spring 核心特性;
- 轻量级: 无需引入额外依赖,基于 Spring 核心包即可使用,性能损耗极低。
二、Spring Event 基础使用方法
Spring 4.2 版本对事件机制进行了大幅简化,无需继承ApplicationEvent和实现ApplicationListener,通过注解即可完成大部分操作,以下基于 Spring Boot 演示完整使用流程。
前置准备
创建 Spring Boot 项目(无需额外引入依赖,spring-boot-starter-web 已包含 Spring 核心包)。
步骤 1:定义事件(可选:普通 POJO / 自定义 ApplicationEvent)
方式 1: 普通 POJO 事件(推荐,简洁高效)
适用于大多数场景,无需继承任何类,直接封装事件数据:
java
/**
* 用户注册事件(普通POJO)
*/
@Data
@AllArgsConstructor
public class UserRegisterEvent {
// 事件携带的数据
private Long userId;
private String username;
private String email;
private LocalDateTime registerTime;
}
对于这类普通的 Java 类,系统会自动将之封装为一个 PayloadApplicationEvent 对象去发送。
方式 2: 自定义 ApplicationEvent(兼容旧版本 / 需获取事件源)
若需获取事件发布者(事件源),可继承ApplicationEvent:
java
/**
* 用户注册事件(继承ApplicationEvent)
*/
@Data
public class UserRegisterEvent extends ApplicationEvent {
private Long userId;
private String username;
private String email;
private LocalDateTime registerTime;
// 构造器必须传入事件源(发布者)
public UserRegisterEvent(Object source, Long userId, String username, String email, LocalDateTime registerTime) {
super(source);
this.userId = userId;
this.username = username;
this.email = email;
this.registerTime = registerTime;
}
}
步骤 2:发布事件
通过ApplicationEventPublisher发布事件(ApplicationContext实现了该接口,可直接注入使用):
java
/**
* 用户业务服务(事件发布者)
*/
@Service
public class UserService {
// 注入事件发布者(ApplicationContext/ApplicationEventPublisher均可)
@Autowired
private ApplicationEventPublisher eventPublisher;
/**
* 用户注册方法(业务逻辑中发布事件)
*/
public void register(String username, String email) {
// 1. 执行注册核心业务(入库等)
Long userId = 1001L; // 模拟数据库生成的用户ID
LocalDateTime registerTime = LocalDateTime.now();
System.out.println("用户注册成功:userId=" + userId + ", username=" + username);
// 2. 发布用户注册事件(普通POJO事件)
UserRegisterEvent registerEvent = new UserRegisterEvent(userId, username, email, registerTime);
eventPublisher.publishEvent(registerEvent);
// 若使用自定义ApplicationEvent,发布方式如下:
UserRegisterEvent registerEvent = new UserRegisterEvent(this, userId, username, email, registerTime);
eventPublisher.publishEvent(registerEvent);
}
}
步骤 3:监听并处理事件
方法1: 自定义类实现 ApplicationListener 接口
java
@Componentpublic
class UserRegisterEventListener implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
// 模拟发送邮件逻辑
String content = "欢迎你," + event.getUsername() + "!你已成功注册本平台,注册时间:" + event.getRegisterTime();
log.info("给用户{}(邮箱:{})发送欢迎邮件,内容:{}", event.getUsername(), event.getEmail(), content);
}
}
方法2: 注解标记事件消费(监听)方法
使用@EventListener注解标记监听器方法,Spring 会自动扫描并注册该监听器,支持多监听器监听同一事件。
监听器示例:用户注册后发送欢迎邮件
java
/**
* 邮件服务监听器(处理用户注册事件)
*/
@Service
@Slf4j
public class EmailServiceListener {
/**
* 监听用户注册事件,发送欢迎邮件
* @param event 用户注册事件
*/
@EventListener // 注解标记为事件监听器,默认监听方法参数类型的事件
public void handleUserRegisterEvent(UserRegisterEvent event) {
// 模拟发送邮件逻辑
String content = "欢迎你," + event.getUsername() + "!你已成功注册本平台,注册时间:" + event.getRegisterTime();
log.info("给用户{}(邮箱:{})发送欢迎邮件,内容:{}", event.getUsername(), event.getEmail(), content);
}
}
步骤 4:测试验证
创建测试类或接口,触发用户注册流程,观察监听器是否生效:
java
@SpringBootTest
public class SpringEventTest {
@Autowired
private UserService userService;
@Test
public void testUserRegisterEvent() {
// 触发用户注册
userService.register("zhangsan", "zhangsan@163.com");
}
}
测试结果
java
用户注册成功:userId=1001, username=zhangsan
2025-12-23 15:30:00.123 INFO 12345 --- [ main] c.example.demo.listener.EmailServiceListener : 给用户zhangsan(邮箱:zhangsan@163.com)发送欢迎邮件,内容:欢迎你,zhangsan!你已成功注册本平台,注册时间:2025-12-23T15:30:00.120
可见,用户注册业务执行后,监听器自动触发,完成了邮件发送,且UserService无需依赖EmailServiceListener,实现了完全解耦。
三、Spring Event 技术原理深挖
要深入理解 Spring Event 的底层原理,核心是理清 ApplicationEventPublisher(发布者) 、ApplicationEventMulticaster(广播器) 、ApplicationListener(监听器) 三者的职责、实现逻辑与协作关系。
概括来说就是当发布一个事件的时候,系统就会去找到所有合适的事件消费者,然后去调用这些事件消费者 。
以下从接口定义、默认实现、核心源码、交互流程四个维度展开分析:
(一) 核心组件1: ApplicationEventPublisher------ 事件发布的入口
ApplicationEventPublisher是 Spring 事件发布的顶层接口 ,定义了事件发布的规范,是用户代码与事件机制交互的入口。
(1) 接口定义(职责)
ApplicationEventPublisher仅定义了 2 个核心方法,负责将事件 "交付" 给事件广播器:
java
@FunctionalInterface
public interface ApplicationEventPublisher {
// 发布ApplicationEvent类型的事件
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 发布任意对象(Spring会包装为PayloadApplicationEvent)
void publishEvent(Object event);
}
这里就两个方法,上面方法调用了下面方法,从这两个方法的参数中也可以看出来,发送时候的消息类型可以分为两种,一种是继承自 ApplicationEvent 类,另一种则是普通的 Java 对象。
(2) 实际实现(委托模式)
ApplicationEventPublisher本身是接口,实际实现由ApplicationContext承担------ 因为ApplicationContext继承了ApplicationEventPublisher接口,而 Spring 容器的核心实现类(如AbstractApplicationContext)会将事件发布的逻辑委托给 ApplicationEventMulticaster去分发。
以AbstractApplicationContext的 publishEvent 方法为例(核心源码):
java
// AbstractApplicationContext.java
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// 1. 统一包装事件:普通对象→PayloadApplicationEvent
ApplicationEvent applicationEvent = resolveDefaultEventType(event);
// 2. 获取事件广播器,委托其执行事件分发
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
// 3. 父容器(若存在)也发布该事件(容器层级传播)
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
可见:
ApplicationEventPublisher(ApplicationContext)本身不处理事件分发,仅做 "事件包装 + 委托广播器" 的轻量工作;- 普通对象(非
ApplicationEvent子类)会被包装为PayloadApplicationEvent,统一事件格式。
(二) 核心组件2: ApplicationEventMulticaster------ 事件分发的 "调度中心"
ApplicationEventMulticaster是 Spring Event 的核心中间件 ,负责管理监听器、匹配事件与监听器、执行监听器逻辑 ,是连接 "发布者" 与 "监听器" 的桥梁。
(1) 接口定义(职责)
ApplicationEventMulticaster定义了监听器管理 + 事件分发的核心规范:
java
public interface ApplicationEventMulticaster {
// 注册监听器
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
// 移除监听器
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
// 移除所有监听器
void removeAllListeners();
// 核心:分发事件给匹配的监听器
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
addApplicationListener:这个方法是添加一个事件消费者,这个方法参数就是一个 ApplicationListener,无论我们通过何种方式注册的事件消费者(继承类或者注解的方式),最终都是调用这个方法把事件消费者添加进来的。addApplicationListenerBean:这个方法是添加事件消费者的 Bean 进来,这个专门处理继承自 ApplicationListener 类的消费者,继承自 ApplicationListener 类的消费者也是要注册到 Spring 容器中去的,将来会通过这个方法记录这些 Bean 的名字。removeApplicationListener:移除一个 ApplicationListener 监听器。removeApplicationListenerBean:根据 beanName 移除一个 ApplicationListener 监听器。removeApplicationListeners:根据条件移除 ApplicationListener 监听器。removeApplicationListenerBeans:根据条件移除 ApplicationListener 监听器。removeAllListeners:移除所有 ApplicationListener。multicastEvent:这就是事件广播方法了。有两个重载,其中一个重载方法多了一个 ResolvableType,这个是描述泛型信息的。
(2) 继承关系
ApplicationEventMulticaster 的继承关系比较简单,它也只有一个实现类,所以分析起来相对要容易一些:

Spring 提供的默认实现类 是SimpleApplicationEventMulticaster,也是实际项目中最常用的广播器。其核心逻辑集中在multicastEvent方法,包含监听器匹配、同步 / 异步执行两大核心流程。
(3) 监听器的注册与管理
SimpleApplicationEventMulticaster内部维护了监听器的集合(包括直接注册的ApplicationListener和容器中的监听器 Bean),并通过ResolvableType(Spring 的类型解析工具)管理监听器与事件的匹配关系。
Spring 容器启动时,会自动初始化ApplicationEventMulticaster:
- 在
AbstractApplicationContext的refresh()方法中,调用initApplicationEventMulticaster():
java
// AbstractApplicationContext.java
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 若用户自定义了ApplicationEventMulticaster,则使用用户的
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
} else {
// 否则创建默认的SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
(4) multicastEvent方法(事件分发逻辑)
SimpleApplicationEventMulticaster的multicastEvent是事件分发的核心,分为匹配监听器→执行监听器两步:
java
// SimpleApplicationEventMulticaster.java
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
// 1. 解析事件的类型(若未指定则自动解析)
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 2. 获取所有匹配当前事件的监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 3. 获取线程池(若配置了则异步执行,否则同步)
Executor executor = getTaskExecutor();
if (executor != null) {
// 异步执行:提交到线程池
executor.execute(() -> invokeListener(listener, event));
} else {
// 同步执行:直接调用监听器
invokeListener(listener, event);
}
}
}
(5) 监听器匹配逻辑:getApplicationListeners
getApplicationListeners方法负责筛选 "能处理当前事件" 的监听器,核心是事件类型的兼容性检查(监听器支持的事件类型是当前事件的父类 / 接口):
java
// AbstractApplicationEventMulticaster.java(SimpleApplicationEventMulticaster的父类)
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// 事件源(发布者)
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
// 构建缓存Key(事件类型+事件源类型)
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 先查缓存,未命中则执行匹配逻辑
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// 同步锁,避免重复计算
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 核心:筛选匹配的监听器
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
} else {
// 无缓存:直接匹配
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
匹配的核心判断是:监听器支持的事件类型是否是当前事件类型的父类 / 接口 (通过ResolvableType.isAssignableFrom实现)。
(6) 监听器执行逻辑:invokeListener
invokeListener负责调用监听器的onApplicationEvent方法,并处理异常:
java
// SimpleApplicationEventMulticaster.java
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
// 异常处理器(若配置)
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 直接调用监听器的onApplicationEvent方法
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
// 类型不匹配的异常处理(通常是缓存失效导致)
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// 可能是监听器泛型类型不匹配,忽略
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
} else {
throw ex;
}
}
}
(三) 核心组件 3:ApplicationListener------ 事件的 "消费者"
ApplicationListener是监听器的顶层接口 ,定义了事件处理的规范,所有监听器(包括注解式监听器)最终都会被包装为ApplicationListener的实现类。
(1) 接口定义(职责)
ApplicationListener是一个泛型接口,仅定义了 1 个核心方法:
java
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 处理事件的核心方法
void onApplicationEvent(E event);
}
- 泛型
E指定了监听器支持的事件类型(实现 "类型安全的事件监听"); - 继承
EventListener是为了标记这是一个监听器(Java 标准标记接口)。
(2) 监听器的两种形式
Spring 支持两种监听器形式,最终都会被注册到ApplicationEventMulticaster:
- 接口式监听器:直接实现
ApplicationListener
用户自定义类实现ApplicationListener接口,Spring 容器启动时会自动将其注册到ApplicationEventMulticaster:
java
// 自定义监听器(接口式)
@Component
public class UserRegisterListener implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
// 处理用户注册事件
}
}
- 注解式监听器:
@EventListener
Spring 4.2 + 支持用@EventListener注解标记方法,无需实现接口。其底层是通过EventListenerMethodProcessor(Bean 后置处理器) 将注解方法包装为ApplicationListenerMethodAdapter(ApplicationListener的实现类)。
核心流程:
a.EventListenerMethodProcessor在 Spring 容器启动时,扫描所有 Bean 中的**@EventListener**方法;
b. 对每个注解方法,创建ApplicationListenerMethodAdapter(包装该方法);
c. 将ApplicationListenerMethodAdapter注册到ApplicationEventMulticaster。
ApplicationListenerMethodAdapter的核心逻辑是 将onApplicationEvent方法委托给注解标记的业务方法:
java
// ApplicationListenerMethodAdapter.java
@Override
public void onApplicationEvent(ApplicationEvent event) {
// 调用注解标记的业务方法
processEvent(event);
}
@Nullable
protected Object processEvent(ApplicationEvent event) {
// 解析方法参数
ResolvableType eventType = ResolvableType.forInstance(event);
for (Method method : this.targetMethods) {
// 匹配方法参数与事件类型
if (supportsEvent(method, eventType)) {
// 执行方法(通过反射)
return invokeMethod(event);
}
}
return null;
}
(四) 三者的协作流程(底层执行链路)
结合上述分析,ApplicationEventPublisher、ApplicationEventMulticaster、ApplicationListener的完整交互流程如下:

(五) 关键底层细节补充
- 事件的类型兼容性: 监听器支持的事件类型(泛型
E)是当前事件的父类 / 接口时,才会被匹配(例如ApplicationListener<ApplicationEvent>会监听所有事件); - 异步的底层支持:
SimpleApplicationEventMulticaster通过setTaskExecutor(Executor)配置线程池,若未配置则默认同步执行; - 监听器的顺序:
@Order/Ordered接口的优先级,是在getApplicationListeners返回的监听器列表中排序的; - 事务绑定事件:
@TransactionalEventListener的底层是TransactionalApplicationListener(ApplicationListener的子类),会绑定事务生命周期,在指定阶段(如AFTER_COMMIT)才执行。
通过以上分析可以看出:Spring Event 的底层是 "委托 + 观察者模式" 的典型实现,ApplicationEventPublisher负责入口封装,ApplicationEventMulticaster负责核心调度,ApplicationListener负责具体业务处理,三者分工明确、解耦彻底,是 Spring 生态中 "轻量级解耦" 的经典实践。
四、Spring Event 进阶特性
1. 异步事件处理
默认情况下,Spring Event 是同步执行 的(发布者等待所有监听器执行完毕后才继续执行),若监听器逻辑耗时较长(如发送短信、调用第三方接口),会阻塞主线程。此时可通过@Async实现异步事件处理。
步骤 1:开启异步支持
在 Spring Boot 启动类上添加@EnableAsync注解:
java
@SpringBootApplication
@EnableAsync // 开启Spring异步支持
public class SpringEventDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringEventDemoApplication.class, args);
}
}
步骤 2:配置异步线程池(可选,推荐)
自定义线程池,避免使用默认线程池的局限性:
java
/**
* 异步线程池配置
*/
@Configuration
public class AsyncConfig {
@Bean("eventAsyncExecutor")
public Executor eventAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(10); // 最大线程数
executor.setQueueCapacity(20); // 队列容量
executor.setKeepAliveSeconds(60); // 线程空闲时间
executor.setThreadNamePrefix("SpringEvent-Async-"); // 线程名前缀
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize();
return executor;
}
}
步骤 3:监听器添加 @Async 注解
在监听器方法上添加@Async,指定自定义线程池:
java
@Service
@Slf4j
public class EmailServiceListener {
/**
* 异步处理用户注册事件,发送欢迎邮件
*/
@Async("eventAsyncExecutor") // 指定自定义线程池
@EventListener
public void handleUserRegisterEvent(UserRegisterEvent event) {
// 模拟耗时操作(睡眠2秒)
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
String content = "欢迎你," + event.getUsername() + "!你已成功注册本平台,注册时间:" + event.getRegisterTime();
log.info("【异步】给用户{}(邮箱:{})发送欢迎邮件,内容:{},线程名:{}",
event.getUsername(), event.getEmail(), content, Thread.currentThread().getName());
}
}
测试异步效果
再次执行测试方法,观察日志:
java
用户注册成功:userId=1001, username=zhangsan
2025-12-23 15:35:00.123 INFO 12345 --- [ main] c.example.demo.listener.LogServiceListener : 用户注册日志:userId=1001, username=zhangsan, registerTime=2025-12-23T15:35:00.120
2025-12-23 15:35:02.125 INFO 12345 --- [SpringEvent-Async-1] c.example.demo.listener.EmailServiceListener : 【异步】给用户zhangsan(邮箱:zhangsan@163.com)发送欢迎邮件,内容:欢迎你,zhangsan!你已成功注册本平台,注册时间:2025-12-23T15:35:00.120,线程名:SpringEvent-Async-1
可见,同步监听器(日志记录)立即执行,异步监听器(邮件发送)在独立线程中执行,主线程无需等待,提升了系统响应速度。
2. 有序事件监听
当多个监听器监听同一事件时,默认执行顺序不确定(取决于 Spring 扫描顺序)。若需指定监听器执行顺序,可通过@Order注解或实现Ordered接口。
方式 1:@Order 注解(推荐)
在监听器方法上添加@Order,数值越小,执行优先级越高:
java
@Service
@Slf4j
public class LogServiceListener {
// 优先级1(先执行)
@Order(1)
@EventListener
public void handleUserRegisterEvent(UserRegisterEvent event) {
log.info("【有序-1】用户注册日志:userId={}, username={}", event.getUserId(), event.getUsername());
}
}
@Service
@Slf4j
public class EmailServiceListener {
// 优先级2(后执行)
@Order(2)
@EventListener
public void handleUserRegisterEvent(UserRegisterEvent event) {
log.info("【有序-2】发送欢迎邮件:username={}", event.getUsername());
}
}
方式 2:实现 Ordered 接口
若监听器是类级别的(实现ApplicationListener),可通过Ordered接口指定顺序:
java
@Service
public class SmsServiceListener implements ApplicationListener<UserRegisterEvent>, Ordered {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("【有序-3】发送短信通知:username=" + event.getUsername());
}
// 指定优先级3(最后执行)
@Override
public int getOrder() {
return 3;
}
}
测试有序效果
java
用户注册成功:userId=1001, username=zhangsan
【有序-1】用户注册日志:userId=1001, username=zhangsan
【有序-2】发送欢迎邮件:username=zhangsan
【有序-3】发送短信通知:username=zhangsan
监听器按@Order/Ordered指定的顺序依次执行,满足有依赖的业务场景。
3. 事件过滤
通过@EventListener的condition属性,使用 SpEL 表达式可实现事件过滤,仅处理满足条件的事件。
示例:仅处理用户名以 "admin" 开头的用户注册事件
java
@Service
@Slf4j
public class AdminNotifyListener {
/**
* 仅监听用户名以admin开头的注册事件
* condition:SpEL表达式,#event代表事件对象
*/
@EventListener(condition = "#event.username.startsWith('admin')")
public void handleAdminRegisterEvent(UserRegisterEvent event) {
log.info("管理员注册通知:userId={}, username={},需分配管理员权限",
event.getUserId(), event.getUsername());
}
}
测试:
- 注册 admin123:监听器触发;
- 注册 zhangsan:监听器不触发。
4. 事务绑定事件
在实际项目中,常需要 "事务提交成功后再执行事件"(如用户注册入库成功后,再发送邮件),此时可使用@TransactionalEventListener注解,绑定事务生命周期。
步骤 1:添加事务管理
java
// 启动类添加@EnableTransactionManagement
@SpringBootApplication
@EnableTransactionManagement
public class SpringEventDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringEventDemoApplication.class, args);
}
}
// UserService的register方法添加事务
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional(rollbackFor = Exception.class)
public void register(String username, String email) {
// 模拟注册入库
Long userId = 1001L;
LocalDateTime registerTime = LocalDateTime.now();
System.out.println("用户注册入库:userId=" + userId + ", username=" + username);
// 模拟异常(测试事务回滚时,事件是否不触发)
// if ("test".equals(username)) {
// throw new RuntimeException("注册失败");
// }
// 发布事件
UserRegisterEvent registerEvent = new UserRegisterEvent(userId, username, email, registerTime);
eventPublisher.publishEvent(registerEvent);
}
}
步骤 2:使用 @TransactionalEventListener
java
@Service
@Slf4j
public class EmailServiceListener {
/**
* 事务提交成功后,再发送邮件
* phase:指定事务阶段,默认TransactionPhase.AFTER_COMMIT(事务提交后)
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleUserRegisterEventAfterCommit(UserRegisterEvent event) {
log.info("【事务提交后】给用户{}发送欢迎邮件", event.getUsername());
}
}
事务阶段说明
| 事务阶段 | 说明 |
|---|---|
TransactionPhase.BEFORE_COMMIT |
事务提交前执行 |
TransactionPhase.AFTER_COMMIT |
事务提交成功后执行(默认) |
TransactionPhase.AFTER_ROLLBACK |
事务回滚后执行 |
TransactionPhase.AFTER_COMPLETION |
事务完成后执行(无论提交 / 回滚) |
五、注意事项与避坑指南
- 异步事件的异常处理: 异步监听器的异常不会传播到发布者,需在监听器内部捕获异常并处理(如记录日志、重试);
- 事件的幂等性: 若事件可能重复发布(如分布式场景),监听器需实现幂等性(如通过订单 ID、用户 ID 去重);
- 避免事件泛滥: 合理设计事件粒度,避免定义过多细粒度事件,建议按业务域划分事件(如用户域、订单域);
- 同步事件的阻塞风险: 同步监听器若耗时过长,会阻塞发布者线程,耗时操作优先使用异步;
- 事务绑定事件的注意点: @TransactionalEventListener仅对有事务的发布者生效,无事务时不会触发。
六、总结
Spring Event 作为 Spring 生态的核心解耦技术,通过观察者模式实现了发布者与订阅者的分离,具有轻量、灵活、易扩展的特点。掌握它的核心原理(四大组件 + 传播流程)和使用方法(基础同步、异步处理、有序监听、事务绑定),能够有效提升项目的代码质量和可维护性,尤其适用于业务联动、异步通知、系统监控等场景。
在实际项目中,合理使用 Spring Event,可减少组件间的直接依赖,让代码结构更清晰,更符合面向对象的设计思想。