文章目录
- [一、为什么要用 Spring 事件机制?](#一、为什么要用 Spring 事件机制?)
- [二、Spring 事件机制的核心原理](#二、Spring 事件机制的核心原理)
- 三、简单Demo
- 四、运行结果
- 五、事件机制的优点总结
- 六、常见进阶用法
- 七、什么时候适合用事件机制?
- 八、总结
在实际开发中,我们经常会遇到这样的场景:
一个核心业务完成后,需要触发多个后续操作,但又不希望代码彼此强耦合。例如:
- 用户注册完成 → 发送欢迎邮件
- 用户注册完成 → 写审计日志
- 用户注册完成 → 发放新人积分
如果直接在一个方法里顺序调用,很快就会演变成难以维护的"上帝方法"。
Spring 提供的 事件机制(ApplicationEvent),正是为了解决这类问题而生。
一、为什么要用 Spring 事件机制?
1. 传统写法的问题(强耦合)
java
public void registerUser(String username) {
saveUser(username);
sendWelcomeEmail(username);
addPoints(username);
writeLog(username);
}
这种写法存在明显问题:
- 一个方法承担过多职责
- 每新增一个功能都要修改原方法
- 不利于扩展、测试和维护
- 容易形成"业务泥球"
2. 事件机制的设计思路(解耦)
事件机制的核心思想是 发布--订阅:
注册完成
↓
发布「用户注册事件」
↓
多个监听器各自处理自己的逻辑
- 注册逻辑 不关心 后续发生什么
- 后续逻辑 只关心事件本身
- 业务之间完全解耦
二、Spring 事件机制的核心原理
Spring 事件机制本质是一个 发布-订阅模型(Publish--Subscribe)。
1. 三个核心角色
| 角色 | 说明 |
|---|---|
| Event | 事件本身,表示"发生了什么" |
| Publisher | 事件发布者 |
| Listener | 事件监听者 |
2. 执行流程示意
publishEvent()
↓
ApplicationContext(Spring 事件总线)
↓
匹配事件类型
↓
调用对应的 Listener
只要事件类型匹配,监听器就会被自动调用。
三、简单Demo
下面通过一个 "用户注册事件" 的示例,完整演示 Spring 事件机制的使用。
1. 定义事件类(Event)
java
import org.springframework.context.ApplicationEvent;
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
public UserRegisteredEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
说明:
- 继承
ApplicationEvent - 用于描述"用户已注册"这一事实
- 可携带任意业务数据
2. 发布事件(Publisher)
java
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 register(String username) {
System.out.println("✅ 用户注册成功:" + username);
// 发布事件
publisher.publishEvent(
new UserRegisteredEvent(this, username)
);
}
}
关键点:
ApplicationEventPublisher由 Spring 自动注入publishEvent()只负责"发通知"- 不关心谁来处理事件
3. 监听事件(Listener)
java
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class UserRegisteredListener
implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println(
"📩 监听到用户注册事件,发送欢迎消息:"
+ event.getUsername()
);
}
}
核心代码是这一行:
java
implements ApplicationListener<UserRegisteredEvent>
含义是:
当
UserRegisteredEvent被发布时,该监听器会自动执行
4. 启动时触发 Demo
java
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DemoRunner {
@Bean
CommandLineRunner run(UserService userService) {
return args -> userService.register("alice");
}
}
5. 启动类
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
四、运行结果
启动项目后,控制台输出如下:

说明:
- 事件成功发布
- 监听器被自动触发
- 业务逻辑成功解耦
五、事件机制的优点总结
1. 解耦业务逻辑
- 发布者无需知道监听者
- 新功能只需新增 Listener
2. 易扩展(企业非常常见)
java
@Component
public class LogListener
implements ApplicationListener<UserRegisteredEvent> { }
java
@Component
public class PointListener
implements ApplicationListener<UserRegisteredEvent> { }
👉 不修改注册逻辑即可扩展功能
3. 符合单一职责原则
- 一个类只做一件事
- 代码清晰、可维护性高
六、常见进阶用法
1. 使用 @EventListener(更简洁)
java
@EventListener
public void handle(UserRegisteredEvent event) {
System.out.println(event.getUsername());
}
2. 异步事件(避免阻塞主流程)
java
@Async
@EventListener
public void handle(UserRegisteredEvent event) {
}
并在启动类或配置类中开启异步:
java
@EnableAsync
七、什么时候适合用事件机制?
✅ 适合场景
- 用户注册 / 下单 / 支付完成
- 文件上传完成 / 处理完成
- 状态变更通知
- 多模块后置处理逻辑
❌ 不适合场景
- 强依赖返回结果的同步流程
- 强一致性事务场景(需谨慎)
八、总结
Spring 事件机制,本质上是一种轻量级的"服务内事件驱动架构"。
它非常适合用于:
- 单体应用
- 同一个 Spring Boot 应用的多模块
- 业务后处理解耦