基本介绍
ApplicationEventPublisher
是 Spring 框架的核心接口,用于发布应用事件,实现观察者模式。其核心作用包括:
- 事件发布:允许组件发布自定义事件
- 松耦合:实现发布者与订阅者的解耦
- 同步处理:默认同步执行(可通过
@Async
实现异步)
- 继承机制:事件对象可继承扩展(支持
ApplicationEvent
或任意 POJO
)
工作流程:
1
| [发布者] → (发布事件) → [ApplicationContext] → (路由事件) → [监听器]
|
应用场景
- 业务解耦:如用户注册后发送邮件/短信
- 状态变更通知:订单状态变化时更新库存
- 审计日志:关键操作后记录审计信息
- 异步任务触发:耗时操作异步执行
- 系统监控:关键事件触发监控上报
代码示例
添加 Maven 依赖
由于 Spring Boot 已经内置了事件发布机制,我们只需要引入 spring-boot-starter
即可,它包含了 spring-context
,其中就有 ApplicationEventPublisher
。
1 2 3 4 5 6 7 8 9 10 11
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
|
关于 Spring Boot 入门可以参考:Spring Boot 入门指南:从零开始创建 Web 应用
事件定义(POJO)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import lombok.Getter; import org.springframework.context.ApplicationEvent;
@Getter public class UserRegisterEvent extends ApplicationEvent {
private final String username;
public UserRegisterEvent(Object source, String username) { super(source); this.username = username; }
}
|
事件监听器
1 2 3 4 5 6 7 8 9 10
| @Component public class UserRegisterListener {
@EventListener public void handleEvent(UserRegisterEvent event) { System.out.println("[注解监听] 新用户注册: " + event.getUsername()); }
}
|
1 2 3 4 5 6 7 8 9
| @Component public class EmailListener implements ApplicationListener<UserRegisterEvent> {
@Override public void onApplicationEvent(UserRegisterEvent event) { System.out.println("[接口监听] 发送欢迎邮件至: " + event.getUsername()); } }
|
在 Spring 4.2 之前,自定义事件必须继承 ApplicationEvent
。从 Spring 4.2 开始,事件可以是任意对象,不再强制要求继承 ApplicationEvent
。因此,有两种解决方案:
- 让
UserRegisterEvent
继承 ApplicationEvent
(这样两种监听方式都支持)
- 将实现
ApplicationListener
接口的监听器改为使用 @EventListener
注解(推荐,因为更灵活)
为了保持代码的简洁和现代 Spring 的使用方式,我们通常推荐使用 @EventListener
注解。这里为了演示两种方式,我们让事件类继承 ApplicationEvent
,同时,在发布事件的时候,需要传递 source
(通常就是发布者对象,但也可以为 null
)
事件发布服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @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));
System.out.println("主流程完成"); } }
|
主应用类
1 2 3 4 5 6 7 8 9 10
| @SpringBootApplication public class ApplicationEventPublisherDemoApplication {
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(ApplicationEventPublisherDemoApplication.class, args); UserService userService = context.getBean(UserService.class); userService.registerUser("cylong"); }
}
|
代码解释
- 事件对象:
UserRegisterEvent
封装事件数据
- 监听器:
- 注解方式:
@EventListener
自动匹配事件类型(也就是根据类名匹配)
- 接口方式:实现
ApplicationListener
接口
- 发布器:
ApplicationEventPublisher.publishEvent()
触发事件
- Spring 自动注入发布器实例
- 执行流程:
- 主应用调用
registerUser()
- 服务内部发布事件
- 所有监听器同步执行
运行输出
1 2 3 4
| 注册用户: cylong [接口监听] 发送欢迎邮件至: cylong [注解监听] 新用户注册: cylong 主流程完成
|
注意事项
作用域限制
1 2 3
| @Component public class UserRegisterListener {...}
|
事件源(source)的作用
1 2 3 4
| if (event.getSource() instanceof UserService) { }
|
监听器执行顺序
监听器按注册顺序执行(可通过 @Order
调整)
1 2 3
| @Order(1) @EventListener public void firstListener(UserRegisterEvent event) {...}
|
异步处理
1 2 3 4 5
| @Async @EventListener public void asyncHandle(UserRegisterEvent event) { }
|
需在配置类添加 @EnableAsync
1 2 3 4 5 6 7 8 9 10 11
| @SpringBootApplication @EnableAsync public class ApplicationEventPublisherDemoApplication {
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(ApplicationEventPublisherDemoApplication.class, args); UserService userService = context.getBean(UserService.class); userService.registerUser("cylong"); }
}
|
事件继承
1 2
| public class VIPRegisterEvent extends UserRegisterEvent {...}
|
- 监听
UserRegisterEvent
会接收到所有子类事件
- 使用
@EventListener(classes = VIPRegisterEvent.class)
限定具体类型
1 2 3 4
| @EventListener(classes = VIPRegisterEvent.class) public void handleEvent(UserRegisterEvent event) { System.out.println("[注解监听] 新 VIP 用户注册: " + event.getUsername()); }
|
性能建议
- 避免在监听器执行耗时操作(默认同步,可以切换为异步)
- 单个事件避免注册过多监听器
错误处理
- 监听器异常会传播到发布者
- 需要时添加单独异常处理
通过 ApplicationEventPublisher
可实现优雅的业务解耦,但需根据场景权衡同步/异步机制。在实际项目中,建议将核心业务与辅助操作(邮件、日志等)通过事件分离,提升系统可维护性。