一、使用步骤
1.1 创建继承 ApplicationEvent 的事件对象
事件对象是 Spring 事件机制中传递信息的载体,它可携带业务数据,方便监听器获取关键信息。在实际开发中,除了继承ApplicationEvent并重写构造方法,通常还会添加自定义字段及对应的 getter 方法。
java
import org.springframework.context.ApplicationEvent;
// 自定义事件,携带业务数据
public class CustomEvent extends ApplicationEvent {
private String message; // 自定义字段:事件消息
private Long timestamp; // 自定义字段:事件发生时间
// 构造方法:接收事件源和业务数据
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
this.timestamp = System.currentTimeMillis();
}
// getter方法:供监听器获取数据
public String getMessage() {
return message;
}
public Long getTimestamp() {
return timestamp;
}
}
1.2 创建监听器对象,用@EventListener注解标注处理方法
监听器负责对事件进行具体处理,通过@EventListener注解可指定监听的事件类型,还能通过condition属性添加触发条件,基于 SpEL 表达式灵活控制事件处理逻辑。一个监听器可以包含多个@EventListener方法,实现对不同事件或同一事件不同场景的处理。
java
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component // 注册为Spring组件,使其被容器扫描
public class CustomEventListener {
// 监听CustomEvent事件,且仅当message包含"error"时触发
@EventListener(
value = CustomEvent.class,
condition = "#event.message.contains('error')"
)
public void handleErrorEvent(CustomEvent event) {
System.out.println("处理错误事件:" + event.getMessage() + ",发生时间:" + event.getTimestamp());
}
// 监听所有CustomEvent(无条件)
@EventListener(CustomEvent.class)
public void handleAllCustomEvent(CustomEvent event) {
System.out.println("处理所有自定义事件:" + event.getMessage());
}
}
1.3 抛出事件
通过ApplicationContext的publishEvent()方法发布事件,Spring 会自动通知所有监听该事件的监听器。在实际业务中,事件发布通常在 Service 层或 Controller 层进行,而非局限于测试类。
java
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
@Service // 业务服务类
public class EventPublisherService implements ApplicationContextAware {
private ApplicationContext applicationContext;
// 业务方法:执行操作后发布事件
public void doBusiness(String message) {
System.out.println("执行业务逻辑:" + message);
// 发布事件(携带业务数据)
applicationContext.publishEvent(new CustomEvent(this, message));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
二、原理
2.1 必要的组件
-
ApplicationEvent:所有自定义事件的基类,用于存储事件源(source)和时间戳(timestamp)等基础信息。
-
@EventListener:用于标记方法为事件处理器,相比传统的ApplicationListener接口实现,大大减少了代码侵入性。
-
EventListenerFactory:负责将@EventListener标注的方法转换为ApplicationListener对象,采用适配器模式,默认实现为DefaultEventListenerFactory。
-
EventListenerMethodProcessor:实现了SmartInitializingSingleton接口,在 Spring 容器启动时,它会扫描容器中所有@EventListener方法,通过EventListenerFactory创建监听器,并注册到容器中。
2.2 EventListenerFactory 和 EventListenerMethodProcessor 注入流程
EventListenerMethodProcessor)
2.3 事件发布与执行流程
- 调用applicationContext.publishEvent(event)时,事件会被传递给ApplicationEventMulticaster(默认SimpleApplicationEventMulticaster)。
- 多播器根据事件类型,找到所有匹配的ApplicationListener(包括通过@EventListener转换的监听器)。
- 多播器执行监听器的onApplicationEvent()方法,默认同步执行,也可配置为异步执行。
三、增强事件处理
3.1 自定义增强:继承 @EventListener + 实现 EventListenerFactory
若需对事件处理逻辑进行扩展,如添加日志记录、权限校验等功能,可通过自定义注解和实现EventListenerFactory来实现。
步骤 1:自定义注解(继承@EventListener的功能,并添加扩展属性):
java
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
@EventListener // 继承原有功能
public @interface LoggedEventListener {
// 复用@EventListener的value属性(指定事件类型)
@AliasFor(annotation = EventListener.class, attribute = "value")
Class<?>[] value() default {};
// 扩展属性:是否记录日志
boolean log() default true;
}
步骤 2:实现 EventListenerFactory(处理自定义注解):
java
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListenerFactory;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
@Component
public class LoggedEventListenerFactory implements EventListenerFactory, Ordered {
@Override
public boolean supportsMethod(Method method) {
// 仅处理@LoggedEventListener标注的方法
return AnnotationUtils.findAnnotation(method, LoggedEventListener.class) != null;
}
@Override
public GenericApplicationListener createApplicationListener(String beanName, Class<?> type, Method method) {
LoggedEventListener annotation = AnnotationUtils.findAnnotation(method, LoggedEventListener.class);
return new GenericApplicationListener() {
@Override
public boolean supportsEventType(ResolvableType eventType) {
// 支持注解指定的事件类型
Class<?>[] eventTypes = annotation.value();
return eventTypes.length == 0 || eventType.isAssignableFrom(eventTypes[0]);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
try {
// 扩展逻辑:记录日志
if (annotation.log()) {
System.out.println("事件处理日志:" + event.getClass().getSimpleName());
}
// 执行原方法(反射调用监听器方法)
method.invoke(type.getDeclaredConstructor().newInstance(), event);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // 优先级高于默认工厂
}
}
使用示例:
java
@Component
public class LoggedListener {
@LoggedEventListener(value = CustomEvent.class, log = true)
public void handle(CustomEvent event) {
System.out.println("处理带日志的事件:" + event.getMessage());
}
}
3.2 事务事件处理(@TransactionalEventListener)
@TransactionalEventListener用于解决事务内发布事件时,监听器执行与事务提交不同步导致的数据不一致问题。它支持在事务的BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK、AFTER_COMPLETION(无论成功失败)等阶段触发事件处理。
java
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.stereotype.Component;
@Component
public class TransactionalListener {
// 事务提交后执行(确保数据已持久化)
@TransactionalEventListener(
value = CustomEvent.class,
phase = TransactionPhase.AFTER_COMMIT
)
public void handleAfterCommit(CustomEvent event) {
System.out.println("事务提交后处理事件:" + event.getMessage());
}
// 事务回滚后执行
@TransactionalEventListener(
value = CustomEvent.class,
phase = TransactionPhase.AFTER_ROLLBACK
)
public void handleAfterRollback(CustomEvent event) {
System.out.println("事务回滚后处理事件:" + event.getMessage());
}
}
注意事项:
- 事件发布者的方法必须被@Transactional标注,否则事务阶段配置将不生效,监听器会立即执行。
- 若需异步执行事务事件,可结合@Async注解使用,但需在配置类上添加@EnableAsync注解。
四、进阶特性
4.1 异步事件处理
通过@EnableAsync开启异步功能,并在@EventListener或@TransactionalEventListener上添加@Async注解,可使事件处理在独立线程执行,避免阻塞主线程,提升系统性能。
java
@Component
public class AsyncListener {
@Async
@EventListener(CustomEvent.class)
public void handleAsync(CustomEvent event) {
System.out.println("异步处理事件:" + Thread.currentThread().getName());
}
}
4.2 事件继承与多态
监听器可以监听父类事件,从而接收所有子类事件,利用面向对象的继承与多态特性,简化事件监听逻辑。
java
// 父类事件
public class BaseEvent extends ApplicationEvent { ... }
// 子类事件
public class ChildEvent extends BaseEvent { ... }
// 监听父类事件,可接收ChildEvent
@EventListener(BaseEvent.class)
public void handleBaseEvent(BaseEvent event) { ... }
4.3 事件发布返回值
监听器方法可以返回值,多个监听器的返回值会被封装为List,通过applicationContext.publishEvent()的返回值获取,方便进行后续处理。
java
// 监听器返回值
@EventListener(CustomEvent.class)
public String handleWithResult(CustomEvent event) {
return "处理结果:" + event.getMessage();
}
// 发布事件并获取返回值
List<Object> results = (List<Object>) applicationContext.publishEvent(new CustomEvent(this, "test"));
Spring 事件机制通过灵活的设计和丰富的扩展能力,为应用程序的解耦、异步处理和事务同步提供了强大支持。合理运用这些特性,能够有效提升系统的可维护性和性能。