SpringEvent事件消息
一、本章介绍
设计并实现一个本地任务消息组件的系统工程框架,以及配套的测试工程服务。核心使用 Spring ApplicationEvent 事件机制,实现行为触达的通知发布与监听,支持后续异步处理外部 HTTP 请求和消息队列(MQ)调用操作。
二、功能流程
如图,是本节关于 Spring Event 事件消息部分的流程。本节以这样一个简单功能诉求,引导工程创建。

首先,搭建一套基础的消息组件工程框架,支持受理任务消息请求,并通过 Spring Event 机制实现事件的发布与监听。通过简单案例的验证,帮助大家初步了解组件框架的核心实现原理。
随后,将本地消息组件构建为 JAR 包,便于测试工程通过 Maven POM 文件方式引入并使用。
注意,本组件作为核心内核服务,将逐步完善全部功能,最终具备切面拦截、数据库操作、Spring Event 监听、Job 任务扫描等能力。为此,采用 DDD(领域驱动设计)工程架构构建内核更为合适。内核类似于将业务项目中从上到下的完整流程提取为独立模块,后续只需在上游系统中引入即可直接运行。
三、基础知识
Spring Event 是 Spring 框架提供的应用程序内部事件发布与订阅机制,基于观察者模式,实现组件间的解耦通信。
1. Spring Event 的作用
组件解耦:事件发布者无需关心监听者是谁,监听者也无需知道事件来源,实现松耦合。
支持异步处理:事件可同步或异步执行,提升系统响应速度与吞吐能力。
扩展性强:便于后续新增事件监听器,实现功能灵活扩展。
2. Spring Event 的核心类和接口
ApplicationEvent:事件基类,自定义事件通常继承它(自 Spring 4.2 起,发布事件时可直接使用任意对象,无需继承 ApplicationEvent)。
ApplicationListener:事件监听器接口,实现该接口的 Bean 可监听指定类型的事件。
ApplicationEventPublisher:事件发布接口,通常由 ApplicationContext 实现,开发者通过其 publishEvent 方法发布事件。
3. 使用步骤
1)定义自定义事件
public class MyCustomEvent extends ApplicationEvent {
private String message;
public MyCustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}2)定义事件监听器
@Component
public class MyCustomEventListener implements ApplicationListener<MyCustomEvent> {
@Override
public void onApplicationEvent(MyCustomEvent event) {
System.out.println("Received event - message: " + event.getMessage());
}
}推荐的注解方式:
@Component
public class MyCustomEventListener {
@EventListener
public void handleMyCustomEvent(MyCustomEvent event) {
System.out.println("Received event - message: " + event.getMessage());
}
}3) 发布事件
@Component
public class MyEventPublisher {
@Autowired
private ApplicationEventPublisher publisher;
public void publish(String message) {
MyCustomEvent event = new MyCustomEvent(this, message);
publisher.publishEvent(event);
}
}4. 事件处理的同步与异步
默认情况下,事件监听是同步执行的:发布事件的线程会阻塞等待所有监听器完成。
若需异步处理,可结合 Spring 的 @Async 支持:
@Component
public class AsyncEventListener {
@Async
@EventListener
public void handleEvent(MyCustomEvent event) {
// 异步处理逻辑
}
}并在配置类中启用异步:
@EnableAsync
@Configuration
public class AsyncConfig {
}5. Spring 内置事件示例
- ContextRefreshedEvent:应用上下文刷新完成时触发。
- ContextStartedEvent:应用上下文启动时触发。
- ContextStoppedEvent:应用上下文停止时触发。
- ContextClosedEvent:应用上下文关闭时触发。
Spring Event 是一种强大且灵活的内部事件驱动机制,适用于组件间解耦通信。通过自定义事件与监听器,可实现松耦合、异步处理,从而显著提升系统的可维护性和扩展性。
四、工程实现
1. 工程结构

自动化配置 通过 spring.factories SPI 机制自动加载 LocalTaskMessageAutoConfig,使整个消息组件工程被 Spring 容器自动实例化并纳入管理。
领域层(Domain) 领域层是整个场景的核心业务逻辑所在,主要包含以下部分:
service 负责核心业务逻辑的具体实现,提供领域服务。
model 定义服务实现过程中所需的领域对象(VO、DTO、Entity 等)。
adapter(适配器) 充当领域服务与外部系统交互的桥梁,以适配器模式完成接口调用、事件发布/订阅、仓储(Repository/DAO)等对接。 类似于水管中的“接头”,负责将领域层的抽象接口与外部具体实现进行无缝连接。
基础设施层(Infrastructure) 负责处理底层技术细节,包括事件发布、数据库操作、HTTP 调用等。 该层中的具体实现会去适配(实现)领域层中定义的接口(Adapter 接口),形成“水管衔接”的关系。 这种分层设计实现了高内聚低耦合:即使将来替换基础设施层的技术栈(如从 MySQL 换成 MongoDB,或从 RestTemplate 换成 WebClient),也不会影响领域层核心业务逻辑。
触发器层(Trigger) 将所有外部“触发”统一抽象为触发器层,包括:
REST 接口调用
消息队列监听
定时任务(Job)
- 该层作为系统的对外入口,负责接收外部触发信号,之后调用领域层(Domain)的核心逻辑进行处理。 所有对外暴露的入口都集中在此层,便于统一管理和扩展。‘
2. 功能开发
下面按包结构依次介绍各模块的职责,并给出最小代码示例,帮助你快速理解整个事件消息的流转过程。
config(自动配置)
- LocalTaskMessageAutoConfig:作为整个消息组件的自动装配入口类,主要负责以下核心功能:
- 开启 Spring 的异步支持(@EnableAsync),确保事件监听器等支持异步处理。
- 开启定时任务支持(@EnableScheduling),为后续 Job 扫描与定时触发提供基础能力。
- 通过 @ComponentScan 注解指定扫描路径,将组件工程内的所有 Spring Bean(包括 Service、Listener、Adapter 等)自动注册到容器中。
- LocalTaskMessageAutoConfig:作为整个消息组件的自动装配入口类,主要负责以下核心功能:
@Configuration
@EnableAsync
@EnableScheduling
@ComponentScan(basePackages = {
"cn.cactusli.wrench.local.task.message.domain.*",
"cn.cactusli.wrench.local.task.message.infrastructure.*",
"cn.cactusli.wrench.local.task.message.trigger.*"
})
public class LocalTaskMessageAutoConfig {
}domain(领域层)
模型:
TaskMessageEntityCommand表示一条任务消息的最小信息。服务接口:
ILocalTaskMessageHandleService定义接收任务消息入口。服务实现:
LocalTaskMessageHandleService调用事件发布接口。事件接口:
ILocalTaskMessageEvent抽象发布事件的能力。
@Data
public class TaskMessageEntityCommand {
private String taskId;
private String taskName;
}
public interface ILocalTaskMessageHandleService {
void acceptTaskMessage(TaskMessageEntityCommand command);
}
@Service
public class LocalTaskMessageHandleService implements ILocalTaskMessageHandleService {
@Resource
private ILocalTaskMessageEvent event;
@Override
public void acceptTaskMessage(TaskMessageEntityCommand command) {
event.publishEvent(command);
}
}
public interface ILocalTaskMessageEvent {
void publishEvent(TaskMessageEntityCommand command);
}- infrastructure(基础设施层)
- 事件对象:
SpringTaskMessageEvent继承ApplicationEvent,承载任务消息。 - 事件发布器:
LocalTaskMessageEvent使用ApplicationEventPublisher发布事件。
- 事件对象:
public class SpringTaskMessageEvent extends ApplicationEvent {
private final TaskMessageEntityCommand taskMessageEntityCommand;
public SpringTaskMessageEvent(Object source, TaskMessageEntityCommand command) {
super(source);
this.taskMessageEntityCommand = command;
}
public TaskMessageEntityCommand getTaskMessageEntityCommand() { return taskMessageEntityCommand; }
}
@Component
public class LocalTaskMessageEvent implements ILocalTaskMessageEvent {
private final ApplicationEventPublisher eventPublisher;
public LocalTaskMessageEvent(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; }
@Override
public void publishEvent(TaskMessageEntityCommand command) {
SpringTaskMessageEvent event = new SpringTaskMessageEvent(this, command);
eventPublisher.publishEvent(event);
}
}- trigger(触发/监听层)
- 监听器:
TaskMessageEventListener使用@EventListener+@Async异步处理事件。
- 监听器:
@Slf4j
@Service
public class TaskMessageEventListener {
@EventListener
@Async
public void handleTaskMessageEvent(SpringTaskMessageEvent event) {
log.info("收到任务消息事件 - 消息内容: {}, 事件时间戳: {}",
event.getTaskMessageEntityCommand(), event.getTimestamp());
}
}2.2 核心流程(事件链)
LocalTaskMessageHandleService.acceptTaskMessage(...) 接收命令LocalTaskMessageEvent.publishEvent(...) 构建并发布 SpringTaskMessageEventTaskMessageEventListener.handleTaskMessageEvent(...) 异步监听并记录日志
2.3 发送一条任务消息(示例代码)
@Component
public class DemoTaskMessageSender implements CommandLineRunner {
private final ILocalTaskMessageHandleService handleService;
public DemoTaskMessageSender(ILocalTaskMessageHandleService handleService) {
this.handleService = handleService;
}
@Override
public void run(String... args) {
TaskMessageEntityCommand cmd = new TaskMessageEntityCommand();
cmd.setTaskId("task-001");
cmd.setTaskName("Demo任务");
handleService.acceptTaskMessage(cmd);
}
}2.4 spring.factories 机制说明
在 Spring Boot(3.x 及兼容场景)中,META-INF/spring.factories 用于声明自动配置类。启动时,框架通过 SpringFactoriesLoader 加载并实例化这些类,从而在不显式 @Import 的情况下完成模块的自动装配。
文件位置:
src/main/resources/META-INF/spring.factories配置内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.cactusli.wrench.local.task.message.config.LocalTaskMessageAutoConfig作用:引入本模块依赖后,
LocalTaskMessageAutoConfig会被自动加载,开启异步/调度,并扫描相关组件,使事件发布与监听开箱即用。备注:Spring Boot 3 推荐改用
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。@Configuration
- 作用:声明一个配置类,使其被 Spring 容器识别与加载;通常用于集中放置
@Bean定义或模块化开启功能。
- 作用:声明一个配置类,使其被 Spring 容器识别与加载;通常用于集中放置
@EnableAsync
- 作用:开启对
@Async的支持,让标注了@Async的方法(如事件监听器)在独立线程池中异步执行。 - 提示:未开启该注解时,
@Async不会生效,监听器将同步执行。
- 作用:开启对
EnableScheduling
- 作用:开启对
@Scheduled的支持,用于编写定时任务(固定频率、固定延迟或 Cron 表达式)。
- 作用:开启对
@ComponentScan
作用:指定要扫描的包路径,自动发现并注册如
@Component、@Service、@Repository等注解的类到容器。在本模块中用于扫描领域与触发层组件,保证事件发布与监听类被容器管理。
五、功能测试
1. 构建组件

- 首先,你需要通过 IntelliJ IDEA 的 Maven 的命令 install 构建 jar 到本地 Maven 仓库。
- 只要,你的所有本地项目都配置了同一个 Maven 仓库,那么另外一个项目就可以引入了。
2. 引入使用

- 在测试工程引入组件,之后在 ApiTest 调用即可。之后你就可以观察到运行日志了。
- 注意,
new CountDownLatch(1).await();是为了暂停,否则刚一调用程序就结束了,事件消息异步的还没执行完。
3. 测试结果

26-02-02.16:22:43.232 [task-1 ] INFO TaskMessageEventListener - 收到任务消息事件 - 消息内容: TaskMessageEntityCommand(taskId=100001, taskName=测试任务), 事件时间戳: 1770020501631执行完成后,看到事件消息,就表示你的组件开发完成了。