使用Spring事件机制实现消息推送,业务系统只需发布事件,消息监听器自动保存消息到数据库。
事件驱动架构已经集成到现有系统中,重启后端服务即可生效:
# Windows
bin\run.bat
# Linux
sh bin/run.sh
查看启动日志,确认以下内容:
... AsyncConfig : Bean 'taskExecutor' created
... TaskMessageListener : Bean created
任务创建、分配、状态变更时自动发布事件,无需额外代码
@Service
public class YourService {
@Autowired
private ApplicationEventPublisher eventPublisher;
// ...
}
示例1: 任务创建时推送消息
public void createTask(Task task) {
// 1. 业务逻辑
taskMapper.insert(task);
// 2. 发布事件(触发消息推送)
eventPublisher.publishEvent(new TaskCreatedEvent(
this, // source
task.getTaskId(), // 任务ID
task.getTaskCode(), // 任务编号
task.getTaskType(), // 任务类型
task.getCreatorId(), // 创建人ID
"张三" // 创建人姓名
));
}
示例2: 任务分配时推送消息
public void assignTask(Long taskId, List<Long> assigneeIds) {
// 1. 业务逻辑
taskMapper.updateAssignees(taskId, assigneeIds);
// 2. 发布事件(触发消息推送)
eventPublisher.publishEvent(new TaskAssignedEvent(
this,
taskId,
"TASK-001",
assigneeIds, // 执行人ID列表
null, // 姓名列表(可选,监听器会查询)
currentUserId, // 分配人ID
"李四" // 分配人姓名
));
}
示例3: 状态变更时推送消息
public void changeStatus(Long taskId, String newStatus) {
Task task = taskMapper.selectById(taskId);
String oldStatus = task.getStatus();
// 1. 业务逻辑
taskMapper.updateStatus(taskId, newStatus);
// 2. 发布事件(触发消息推送)
eventPublisher.publishEvent(new TaskStatusChangedEvent(
this,
taskId,
task.getTaskCode(),
oldStatus, // 旧状态
newStatus, // 新状态
"待处理", // 旧状态描述
"已完成", // 新状态描述
task.getAssigneeIds(), // 执行人ID列表
task.getCreatorId() // 创建人ID
));
}
| 事件类 | 用途 | 消息类型 |
|---|---|---|
| TaskCreatedEvent | 任务创建 | CREATE |
| TaskAssignedEvent | 任务分配 | PUSH/ASSIGN |
| TaskStatusChangedEvent | 状态变更 | STATUS |
package com.ruoyi.system.event;
import org.springframework.context.ApplicationEvent;
public class OrderCreatedEvent extends ApplicationEvent {
private Long orderId;
private String orderNo;
private Long customerId;
public OrderCreatedEvent(Object source, Long orderId, String orderNo, Long customerId) {
super(source);
this.orderId = orderId;
this.orderNo = orderNo;
this.customerId = customerId;
}
// getters...
}
@Component
public class OrderMessageListener {
@Autowired
private SysMessageMapper sysMessageMapper;
@Async
@EventListener
public void handleOrderCreatedEvent(OrderCreatedEvent event) {
SysMessage message = new SysMessage();
message.setMessageType("ORDER_CREATE");
message.setMessageTitle("订单创建成功");
message.setMessageContent("您的订单" + event.getOrderNo() + "已创建");
message.setReceiverId(event.getCustomerId());
message.setIsRead("0");
message.setCreateTime(DateUtils.getNowDate());
message.setDelFlag("0");
sysMessageMapper.insertSysMessage(message);
}
}
@Service
public class OrderServiceImpl {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createOrder(Order order) {
orderMapper.insert(order);
// 发布事件
eventPublisher.publishEvent(new OrderCreatedEvent(
this, order.getId(), order.getOrderNo(), order.getCustomerId()
));
}
}
// ❌ 旧方式:需要注入MessageService
@Autowired
private IMessageService messageService;
public void createTask() {
// ...
messageService.pushMessage(...); // 强依赖
}
// ✅ 新方式:只需发布事件
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createTask() {
// ...
eventPublisher.publishEvent(event); // 零依赖
}
业务处理 200ms → 返回结果
↓(不阻塞)
发布事件 → 异步保存消息 50ms
总耗时:200ms(而非250ms)
添加新的消息推送场景,只需:
1. 发布事件 ✅
2. 无需修改业务代码 ✅
3. 无需重新部署 ✅
# 搜索事件发布日志
grep "publishEvent" logs/ruoyi-admin.log
# 搜索事件监听日志
grep "TaskMessageListener" logs/ruoyi-admin.log
2025-10-25 14:30:15 [main] INFO 发布任务创建事件,任务ID:1001
2025-10-25 14:30:15 [async-task-1] INFO 收到任务创建事件,任务ID:1001
2025-10-25 14:30:15 [async-task-1] INFO 任务创建消息已保存,消息ID:5001
原因: 可能是异步线程池满了
解决:
1. 查看日志是否有异常
2. 调整线程池配置(AsyncConfig.java)
3. 检查数据库连接
方案1: 使用同步监听器(去掉@Async)
@EventListener // 不使用@Async
public void handleEvent(Event event) {
// 同步执行,确保消息保存
}
方案2: 添加重试机制
@Async
@EventListener
@Retryable(maxAttempts = 3)
public void handleEvent(Event event) {
// 失败自动重试3次
}
修改监听器,去掉 @Async 注解:
// @Async // 注释掉
@EventListener
public void handleEvent(Event event) {
// 现在是同步执行
}
// 收集消息,批量保存
List<SysMessage> messages = new ArrayList<>();
for (Long userId : userIds) {
SysMessage msg = new SysMessage();
// ...
messages.add(msg);
}
sysMessageMapper.batchInsert(messages); // 批量插入
根据实际负载调整 AsyncConfig.java:
// 高并发场景
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
// 低并发场景
executor.setCorePoolSize(3);
executor.setMaxPoolSize(5);
| 特性 | 直接调用 | 事件驱动 |
|---|---|---|
| 代码耦合 | 强依赖MessageService | 零依赖 |
| 性能 | 同步阻塞 | 异步非阻塞 |
| 扩展性 | 需修改代码 | 只需添加监听器 |
| 测试 | 需模拟Service | 只需发布事件 |
TaskEvent.java - 事件基类TaskCreatedEvent.java - 创建事件TaskAssignedEvent.java - 分配事件TaskStatusChangedEvent.java - 状态事件TaskMessageListener.java - 消息监听器AsyncConfig.java - 异步配置SysTaskServiceImpl.java - 改为发布事件prd/事件驱动消息推送-实现总结.md更新时间: 2025-10-25
版本: v2.0
推荐使用: 适合所有需要消息推送的场景