跨流程通信新范式:Activiti信号事件驱动的业务协同实践
痛点与解决方案
企业业务流程中常面临跨流程状态同步难题,如订单支付完成后需同步触发物流流程、库存更新和财务核算。传统集成方案依赖数据库轮询或消息队列,存在延迟高、耦合紧等问题。Activiti的信号事件(Signal Event)机制提供了轻量化解决方案,通过SignalEventDefinition实现跨流程的松耦合通信,支持全局/流程实例级信号作用域,满足复杂业务场景的协同需求。
信号事件核心机制
数据模型解析
信号事件定义类SignalEventDefinition位于activiti-core/activiti-bpmn-model/src/main/java/org/activiti/bpmn/model/SignalEventDefinition.java,核心属性包括:
signalRef: 信号唯一标识(必选)signalExpression: 动态信号引用表达式async: 异步触发标志(默认false)
public class SignalEventDefinition extends EventDefinition {
protected String signalRef; // 信号引用ID
protected String signalExpression; // EL表达式动态指定信号
protected boolean async; // 是否异步执行
// getters/setters/克隆方法...
}
BPMN XML定义规范
在流程文件中通过<signalEventDefinition>标签声明信号事件,如activiti-core/activiti-bpmn-converter/src/test/resources/signaltest.bpmn所示:
<definitions>
<!-- 全局信号定义 -->
<signal id="signal1" name="Signal 1" activiti:scope="global"/>
<!-- 中间投掷事件 -->
<bpmn:intermediateThrowEvent id="throwSignal">
<bpmn:signalEventDefinition signalRef="signal1"/>
</bpmn:intermediateThrowEvent>
<!-- 边界捕获事件 -->
<bpmn:boundaryEvent id="catchSignal" attachedToRef="task1">
<bpmn:signalEventDefinition signalRef="signal1"/>
</bpmn:boundaryEvent>
</definitions>
跨流程通信实现
1. 信号作用域配置
Activiti支持两种信号作用域(通过activiti:scope属性指定):
- global(默认):全引擎可见,可跨流程实例通信
- processInstance:仅当前流程实例内可见
配置示例见activiti-core/activiti-bpmn-converter/src/test/resources/signaltest.bpmn:
<signal id="signal1" name="OrderPaid" activiti:scope="global"/>
<signal id="signal2" name="InventoryUpdated" activiti:scope="processInstance"/>
2. 信号投掷与捕获
投掷信号(Throw Event)
通过中间投掷事件发送信号:
<bpmn:intermediateThrowEvent id="throwPaymentCompleted">
<bpmn:signalEventDefinition signalRef="OrderPaid"/>
</bpmn:intermediateThrowEvent>
捕获信号(Catch Event)
- 开始事件捕获:初始化流程实例
- 边界事件捕获:中断/非中断任务执行
- 中间事件捕获:流程流转控制
<bpmn:startEvent id="start">
<bpmn:signalEventDefinition signalRef="test" activiti:async="true"/>
</bpmn:startEvent>
3. 异步信号处理
通过activiti:async="true"启用异步信号传递,避免长耗时操作阻塞主流程:
<signalEventDefinition signalRef="test" activiti:async="true"/>
(event instanceof SignalEventDefinition) && ((SignalEventDefinition) event).isAsync()
可视化流程设计
信号事件在流程图中使用特定图标标识:
- 投掷事件:圆圈内带向右箭头
- 捕获事件:圆圈内带向左箭头
if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
drawMarker(g, x, y, EVENT_MARKER_THROW_SIGNAL, true);
}
最佳实践与案例
订单支付触发多流程
- 支付流程:完成支付后投掷
OrderPaid信号 - 物流流程:捕获信号启动配送流程
- 财务流程:捕获信号生成发票
关键实现要点:
- 使用全局作用域确保跨流程可见性
- 为关键信号事件启用异步处理
- 通过
signalExpression动态路由信号:<signalEventDefinition signalExpression="${orderType == 'VIP' ? 'VipOrderPaid' : 'NormalOrderPaid'}"/>
异常处理机制
通过边界信号事件实现流程中断控制,如库存不足时终止订单流程:
<bpmn:boundaryEvent id="catchStockError" attachedToRef="processOrder" cancelActivity="true">
<bpmn:signalEventDefinition signalRef="StockInsufficient"/>
</bpmn:boundaryEvent>
常见问题与解决方案
| 问题场景 | 解决方案 | 参考代码 |
|---|---|---|
| 信号未被捕获 | 检查信号ID拼写/作用域配置 | signaltest.bpmn |
| 并发信号冲突 | 启用异步处理+乐观锁 | async-property-process.bpmn |
| 动态信号路由 | 使用signalExpression EL表达式 | SignalEventDefinition.java |
总结与扩展
信号事件作为Activiti的核心通信机制,为跨流程协作提供了轻量级解决方案。通过合理配置信号作用域、异步执行和动态路由,可满足从简单通知到复杂业务协同的各类需求。建议结合官方示例项目深入实践,探索与消息事件、错误事件的组合应用模式,构建更健壮的流程架构。
后续学习路径:
- 信号事件与消息事件的区别(作用域/消费模式)
- 信号事件的事务特性与补偿机制
- 高并发场景下的信号处理性能优化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



