一、Spring Event 应用场景
1. 业务解耦
当一个业务操作触发多个后续动作时,用事件解耦各个动作,避免代码耦合。
比如:用户注册后同时发送欢迎邮件、积分赠送、日志记录等,这些逻辑可以通过事件发布+多个监听器异步处理。
2. 跨模块通信
不同模块间需要协同工作,但又不想直接调用彼此代码,事件机制能做到模块间松耦合通信。
比如订单模块发布“订单已支付”事件,库存模块监听此事件减少库存。
3. 异步处理
有些业务处理耗时且对用户响应速度影响较大,通过事件异步处理能提升性能和体验。
比如发短信、写日志、推送通知等。
4. 日志和审计
对系统行为做统一日志或审计,利用事件捕获业务操作,方便统一管理和扩展。
5. 系统监控和报警
关键事件触发时发送告警通知或写监控日志。
6. 分布式系统的领域事件
在微服务架构中,服务间通过领域事件(Domain Event)进行通信,保持服务间的解耦和业务一致性。
简单总结
Spring Event 适用于“一个动作触发多个后续独立操作”,尤其需要解耦、扩展和异步时。
二、简单使用 (同步)
1. 定义事件类
import org.springframework.context.ApplicationEvent;
public class UserRegisterEvent extends ApplicationEvent {
private final String username;
public UserRegisterEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
2. 发布事件的组件(发布者)
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final ApplicationEventPublisher publisher;
public UserService(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void registerUser(String username) {
System.out.println("注册用户:" + username);
// 注册逻辑...
// 发布事件
publisher.publishEvent(new UserRegisterEvent(this, username));
}
}
3. 监听事件的组件(监听者)
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class EmailListener {
@EventListener
public void handleUserRegister(UserRegisterEvent event) {
System.out.println("给用户发送欢迎邮件:" + event.getUsername());
// 发送邮件逻辑...
}
}
4. 测试调用
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EventDemoApplication implements CommandLineRunner {
private final UserService userService;
public EventDemoApplication(UserService userService) {
this.userService = userService;
}
public static void main(String[] args) {
SpringApplication.run(EventDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
userService.registerUser("张三");
}
}
运行结果
注册用户:张三
给用户发送欢迎邮件:张三
三、简单使用 (异步)
如果你想加异步处理,只需要给监听方法加上 @Async 并开启异步支持即可:
@EnableAsync
@Component
public class EmailListener {
@Async // 加上此注解
@EventListener
public void handleUserRegister(UserRegisterEvent event) {
// 异步发送邮件
}
}
@Async 生效前提是你的 Spring 配置里必须加上 @EnableAsync 注解,否则 @Async 会被忽略,方法还是同步执行。
🧠 问题核心:
Spring 的异步事件监听(带 @Async 的 @EventListener) 本质上是通过线程池异步执行监听方法。它的执行成功或失败不会影响主业务流程,但也不会自动重试!
异步监听器(@Async)的执行顺序 无法通过 @Order 控制
@Order 只控制监听器在 同一个线程同步执行时 的顺序。
一旦加了 @Async,监听方法会被放到线程池里并发执行,顺序完全不确定。
你看到先发邮件后发短信,其实是线程调度的结果,不是按 @Order 顺序执行。