对于部分审批流程或者多个表单数据处理需要回写数据,可以利用监听器处理
1.在方法上加入注解@EventListener
"#processTaskEvent.flowCode.startsWith('leave')" 解释如下:
processTaskEvent: 方法参数
flowCode: processTaskEvent的属性
startsWith: flowCode类型的方法(这里是String)
@org.springframework.context.event.EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')")
public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
log.info("当前任务创建了{}", processTaskEvent.toString());
// 这里写回调事件的数据处理
}
2.触发监听器
/**
* 执行创建任务监听
*
* @param flowCode 流程定义编码
* @param instance 实例数据
* @param taskId 任务id
*/
public void processTaskHandler(String flowCode, Instance instance, Long taskId) {
String tenantId = SecurityUtils.getTenantId();
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
processTaskEvent.setFlowCode(flowCode);
// 执行监听
SpringUtils.context().publishEvent(processTaskEvent);
}
3.具体数据处理flowProcessEventHandler受Spring管理,中有触发监听器方法
// 具体的数据处理完成之后 发布事件
flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, task.getId());
具体执行: 3.数据处理 => 2.触发监听器 => 1.执行监听方法回调
在 Spring 框架中,事件监听机制是实现松耦合架构的重要手段,而 @EventListener
和 @TransactionalEventListener
在处理事务相关事件时存在显著差异。以下从事务生命周期、执行顺序、数据一致性等维度展开对比分析。
维度 | @EventListener | @TransactionalEventListener |
事务感知能力 |
不感知事务状态,默认在事务内执行 |
深度集成事务机制,可感知事务阶段 |
执行时机 |
事件发布时立即执行(可能在事务提交前) |
可指定在事务提交后 / 前、回滚时执行 |
数据一致性保障 |
不保证事务提交后执行,可能读取未提交数据 |
确保在事务状态稳定后执行,数据一致性更强 |
底层实现 |
基于 ApplicationEventPublisher 直接发布 |
基于 TransactionSynchronization 机制监听事务阶段 |
参数配置 |
无事务相关参数 |
支持 phase 、rollbackFor 等事务参数 |
A[事务开始] --> B[业务操作]
B --> C{事务是否成功?}
C -- 是 --> D[事务提交前]
C -- 否 --> E[事务回滚]
D --> F[事务提交]
F --> G[事务提交后]
E --> H[事务回滚后]
% 事件触发点
D -. @EventListener(默认) .-> I[事件处理(可能失败导致事务回滚)]
F -. @TransactionalEventListener(AFTER_COMMIT) .-> J[事件处理(数据已持久化)]
E -. @TransactionalEventListener(AFTER_ROLLBACK) .-> K[事件处理(数据未变更)]
@Service
public class UserService {
@Transactional
public void updateUserAndPublishEvent(Long userId) {
userRepository.updateStatus(userId, "INACTIVE");
- 核心问题:
- 事件处理可能在事务提交前执行,若事务回滚,事件处理逻辑与数据库状态不一致。
- 若事件处理中包含数据库查询,可能读取到未提交的临时数据(脏读风险)。
@Service
public class UserListener {
- 执行顺序优势:
- 通过
phase
参数精确控制事件在事务的哪个阶段执行,避免数据不一致。
AFTER_COMMIT
阶段确保事件处理时数据已持久化,后续操作安全。
AFTER_ROLLBACK
可用于处理事务失败后的补偿逻辑(如清理缓存)。
当结合 @Async
实现异步事件处理时,两者的行为差异更明显:
@Service
public class AsyncUserListener {
- 关键差异:
@EventListener + @Async
可能因事务未提交导致异步线程读取旧数据。
@TransactionalEventListener + @Async
会等待事务提交后再异步处理,确保数据可见性。
场景类型 | 推荐注解 | 原因 |
普通业务事件(无事务依赖) |
@EventListener |
无需感知事务状态,执行效率更高 |
事务相关事件(如数据持久化后通知) |
@TransactionalEventListener |
确保事件在事务提交后执行,避免数据不一致 |
跨服务数据同步(最终一致性) |
@TransactionalEventListener |
结合 AFTER_COMMIT 阶段,确保本地事务成功后再触发远程操作 |
事务回滚补偿逻辑 |
@TransactionalEventListener |
通过 AFTER_ROLLBACK 阶段处理事务失败后的清理工作 |
-
@EventListener:
- 事件发布时立即执行,可能在事务提交前执行。
- 若事务回滚,事件处理结果与数据库状态不一致。
- 适用于不依赖事务结果的轻量级事件。
-
@TransactionalEventListener:
- 可精确控制在事务提交后 / 前 / 回滚时执行。
AFTER_COMMIT
是最常用阶段,确保数据持久化后处理事件。
- 适用于需要保证数据一致性的场景,如订单支付成功后发送通知。
通过合理选择事件监听方式,可在系统松耦合设计中同时保障事务一致性,避免因时序问题导致的数据不一致风险。