1. 概述
在本教程中,我们将深入探讨 Spring 中如何使用事件机制。
虽然事件功能在 Spring 框架中经常被忽略,但它却是非常实用的功能之一。和 Spring 的很多特性一样,事件发布能力是由 ApplicationContext 提供的。
以下是使用 Spring 事件的一些基本准则:
- 如果使用 Spring 4.2 之前的版本,事件类需要继承 ApplicationEvent;
- 从 Spring 4.2 开始,事件类 不再需要继承 ApplicationEvent;
- 发布者应注入 ApplicationEventPublisher 对象;
- 监听者需实现 ApplicationListener 接口;
2. 自定义事件
Spring 允许我们创建并发布自定义事件,默认情况下这些事件是 同步执行 的。这带来了一些好处,例如监听者可以参与到发布者的事务上下文中。
2.1. 一个简单的应用事件
我们先创建一个简单的事件类,用于存储事件数据。
在这个例子中,事件类持有一个 String 类型的消息:
public class CustomSpringEvent extends ApplicationEvent {
private String message;
public CustomSpringEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
2.2. 事件发布者
接下来创建事件的发布者。发布者构造事件对象,并将其发布给所有监听者。
为了发布事件,发布者只需注入 ApplicationEventPublisher 并调用 publishEvent() 方法即可:
@Component
public class CustomSpringEventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void publishCustomEvent(final String message) {
System.out.println("Publishing custom event. ");
CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
applicationEventPublisher.publishEvent(customSpringEvent);
}
}
✅ 提示:Spring 4.2 后,ApplicationEventPublisher 接口新增了 publishEvent(Object event) 方法,允许传入任意对象作为事件,无需继承 ApplicationEvent。
2.3. 事件监听者
最后创建事件监听者。
监听者只需是一个 Spring Bean 并实现 ApplicationListener 接口:
@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
@Override
public void onApplicationEvent(CustomSpringEvent event) {
System.out.println("Received spring custom event - " + event.getMessage());
}
}
⚠️ 注意:监听方法是同步执行的,也就是说 publishCustomEvent() 方法会一直阻塞,直到所有监听者处理完毕。
3. 异步事件处理
有些场景下,我们并不希望事件同步处理,而是需要异步执行。
3.1. 使用 ApplicationEventMulticaster
可以通过配置一个带有线程池的 ApplicationEventMulticaster 来开启异步事件处理:
@Configuration
public class AsynchronousSpringEventsConfig {
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster =
new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
}
✅ 此时所有事件监听者都会异步执行。
3.2. 使用 @Async
如果只想让某些监听者异步执行,可以使用 @Async 注解:
@EventListener
@Async
public void handleAsyncEvent(CustomSpringEvent event) {
System.out.println("Handle event asynchronously: " + event.getMessage());
}
还可以指定使用特定的线程池:
@Async("nonDefaultExecutor")
void handleAsyncEvent(CustomSpringEvent event) {
// run asynchronously by "nonDefaultExecutor"
}
📌 别忘了在配置类上加上 @EnableAsync:
@Configuration
@EnableAsync
public class AppConfig {
}
4. Spring 内置事件
Spring 自身也会发布一些内置事件,比如:
- ContextRefreshedEvent
- ContextStartedEvent
- RequestHandledEvent
这些事件可以帮助我们介入应用生命周期,执行自定义逻辑。
示例:监听上下文刷新事件
public class ContextRefreshedListener
implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent cse) {
System.out.println("Handling context re-freshed event. ");
}
}
5. 基于注解的事件监听
从 Spring 4.2 开始,事件监听者不再需要实现 ApplicationListener 接口,可以直接在任意 Spring Bean 的方法上使用 @EventListener 注解:
@Component
public class AnnotationDrivenEventListener {
@EventListener
public void handleContextStart(ContextStartedEvent cse) {
System.out.println("Handling context started event.");
}
}
默认是同步执行的,如果需要异步,只需加上 @Async 注解即可。
6. 泛型事件支持
Spring 还支持带有泛型信息的事件。
6.1. 泛型事件类
我们创建一个泛型事件类:
public class GenericSpringEvent<T> {
private T what;
protected boolean success;
public GenericSpringEvent(T what, boolean success) {
this.what = what;
this.success = success;
}
// ... standard getters
}
6.2. 监听者
使用 @EventListener 和 SpEL 表达式进行条件监听:
@Component
public class AnnotationDrivenEventListener {
@EventListener(condition = "#event.success")
public void handleSuccessful(GenericSpringEvent<String> event) {
System.out.println("Handling generic event (conditional).");
}
}
6.3. 发布者
发布泛型事件时,由于类型擦除,建议使用子类明确泛型类型,例如:
class GenericStringSpringEvent extends GenericSpringEvent<String> { ... }
另外,如果在 @EventListener 方法中返回一个非空值,Spring 会自动将其作为新事件发布。
7. 事务绑定事件
Spring 4.2 引入了 @TransactionalEventListener 注解,允许监听者绑定到事务的不同阶段。
支持的事务阶段包括:
- AFTER_COMMIT(默认):事务成功提交后触发
- AFTER_ROLLBACK:事务回滚后触发
- AFTER_COMPLETION:事务完成后触发(成功或失败)
- BEFORE_COMMIT:事务提交前触发
示例:
@TransactionalEventListener
public void handleCustom(CustomSpringEvent event) {
System.out.println("Handling event only when a transaction successfully completes.");
}
⚠️ 注意:*@TransactionalEventListener* 默认是同步执行的,不通过 ApplicationEventMulticaster 调度。
如果希望异步执行,可以结合使用 @Async:
@Async
@TransactionalEventListener
void handleCustom(CustomSpringEvent event) {
System.out.println("Handling event only when a transaction successfully completes.");
}
⚠️ 踩坑提醒:使用 @Async 后,监听方法将无法访问原始事务上下文(如懒加载实体、事务回滚等),需谨慎使用。
8. 总结
本文介绍了 Spring 事件机制的基本使用方法,包括:
- 自定义事件的创建与发布
- 同步与异步事件处理
- 注解驱动的事件监听
- 泛型事件支持
- 事务绑定事件处理
这些功能让 Spring 的事件机制变得非常灵活,适合用于解耦模块、实现观察者模式等场景。