1. 为什么你需要掌握Flowable多实例第一次接触Flowable多实例时我正面临一个棘手的审批场景某跨国项目的采购申请需要经过不同地区负责人的并行审批。传统做法是为每个地区硬编码一个审批节点这不仅让流程图变得臃肿更致命的是每次新增地区都要重新部署流程。直到发现多实例特性才真正体会到什么叫动态工作流的魅力。多实例本质上是一种智能循环机制它允许我们动态生成任务根据运行时数据如审批人列表自动创建对应数量的任务实例灵活控制流程支持并行/串行执行可设置智能完成条件如过半通过即生效减少模板代码用配置代替硬编码使流程具备适应业务变化的能力在实际项目中我常用它处理这些场景动态审批链如根据金额自动匹配审批层级批量数据处理如同时向多个系统发起数据同步弹性任务分发如客服工单的智能负载均衡2. 多实例的核心配置详解2.1 基础配置三要素配置一个多实例活动需要掌握这三个关键属性userTask idmultiTask name动态审批 flowable:assignee${approver} multiInstanceLoopCharacteristics isSequentialfalse flowable:collection${approverService.getApprovers(execution)} flowable:elementVariableapprover completionCondition${nrOfCompletedInstances 2}/completionCondition /multiInstanceLoopCharacteristics /userTaskcollection最强大的动态数据源配置支持直接指定集合变量名如approverList使用Spring Bean方法调用如示例中的approverService支持EL表达式实现运行时计算elementVariable当前元素的引用变量在任务分配、条件判断中频繁使用isSequential布尔值决定并行(false)/串行(true)模式。曾经在报销流程中踩过坑误将财务复核设为并行模式导致出纳同时收到多个冲突请求2.2 智能完成条件实战默认情况下多实例会等待所有任务完成。但通过completionCondition可以实现更灵活的流程控制!-- 过半通过即生效 -- completionCondition ${nrOfCompletedInstances/nrOfInstances 0.5} /completionCondition !-- 一票否决场景 -- completionCondition ${nrOfCompletedInstances 0 hasReject} /completionCondition我曾用这种机制实现过智能投票系统当赞成票达到60%时立即通过反对票超过30%时自动终止流程72小时未达成条件则进入人工仲裁3. 动态数据绑定的高阶玩法3.1 运行时数据注入在多实例场景中我经常需要将上下文数据传递给每个实例。比如在合同审批流程中需要让每个审批人看到完整的合同历史// 在流程启动前注入基础数据 runtimeService.setVariable(processInstanceId, contractHistory, getContractVersions()); // 在服务任务中动态补充审批人 public ListString getApproversWithContext(DelegateExecution execution) { Contract contract (Contract) execution.getVariable(contract); return approverDao.findByDepartment(contract.getDepartment()); }3.2 多实例与监听器的组合技通过事件监听器可以实现更精细的控制// 在每个实例创建时追加专属数据 EventListener public void onTaskCreated(DelegateTask task) { if (task.getProcessDefinitionId().contains(multiInstance)) { String approver (String) task.getVariable(approver); task.setVariableLocal(approverHistory, getApprovalHistory(approver)); } }这种模式特别适合需要审计追踪的场景。最近一个银行客户的项目中我们用它实现了完整的审批轨迹记录每个审批步骤都自动关联了当时的系统快照。4. 避坑指南与性能优化4.1 常见问题排查在实施过程中这几个问题最常出现集合数据为空建议添加前置校验sequenceFlow idcheckApprovers sourceRefgateway targetRefmultiTask conditionExpression xsi:typetFormalExpression ${!CollectionUtils.isEmpty(approverList)} /conditionExpression /sequenceFlow变量作用域混淆注意区分流程变量与本地变量父执行实例存储nrOfInstances等全局数据子执行实例通过elementVariable访问当前元素事务边界问题并行任务数量过大时可能触发数据库锁超时4.2 性能优化建议处理过的一个生产案例当审批人超过500时流程启动耗时从200ms飙升到8秒。通过以下优化方案最终控制在1秒内分批加载改造集合获取逻辑采用分页查询public ListString getApproversChunk(DelegateExecution exec) { int chunkSize 100; int offset (int) exec.getVariable(chunkIndex) * chunkSize; return approverDao.findChunk(offset, chunkSize); }异步化处理对非强一致性的任务启用异步特性multiInstanceLoopCharacteristics isSequentialfalse flowable:asynctrue缓存集合数据避免重复查询相同数据源5. 真实案例智能工单分发系统去年为某电商平台设计的客服工单系统完美展现了多实例的实战价值业务需求根据工单类型自动匹配技能组售后、技术、投诉等每个技能组内按负载均衡分配坐席30秒无响应自动升级到组长解决方案serviceTask iddispatchTask flowable:classcom.example.TicketDispatcher multiInstanceLoopCharacteristics isSequentialfalse flowable:collection${ticketRouter.getTargetGroups(execution)} flowable:elementVariabletargetGroup completionCondition ${ticketDispatcher.hasAccepted(execution) || ticketDispatcher.timeout(execution)} /completionCondition /multiInstanceLoopCharacteristics /serviceTask关键实现点通过ticketRouter动态解析工单类型对应的技能组每个技能组并行执行坐席选择逻辑完成条件检查是否有坐席接单或超时上线后平均响应时间从原来的4分钟缩短到22秒客户满意度提升35%。这个案例充分证明合理运用多实例特性可以让死板的流程活起来。
Flowable多实例实战:从循环配置到动态任务分发的完整指南
发布时间:2026/5/16 22:11:16
1. 为什么你需要掌握Flowable多实例第一次接触Flowable多实例时我正面临一个棘手的审批场景某跨国项目的采购申请需要经过不同地区负责人的并行审批。传统做法是为每个地区硬编码一个审批节点这不仅让流程图变得臃肿更致命的是每次新增地区都要重新部署流程。直到发现多实例特性才真正体会到什么叫动态工作流的魅力。多实例本质上是一种智能循环机制它允许我们动态生成任务根据运行时数据如审批人列表自动创建对应数量的任务实例灵活控制流程支持并行/串行执行可设置智能完成条件如过半通过即生效减少模板代码用配置代替硬编码使流程具备适应业务变化的能力在实际项目中我常用它处理这些场景动态审批链如根据金额自动匹配审批层级批量数据处理如同时向多个系统发起数据同步弹性任务分发如客服工单的智能负载均衡2. 多实例的核心配置详解2.1 基础配置三要素配置一个多实例活动需要掌握这三个关键属性userTask idmultiTask name动态审批 flowable:assignee${approver} multiInstanceLoopCharacteristics isSequentialfalse flowable:collection${approverService.getApprovers(execution)} flowable:elementVariableapprover completionCondition${nrOfCompletedInstances 2}/completionCondition /multiInstanceLoopCharacteristics /userTaskcollection最强大的动态数据源配置支持直接指定集合变量名如approverList使用Spring Bean方法调用如示例中的approverService支持EL表达式实现运行时计算elementVariable当前元素的引用变量在任务分配、条件判断中频繁使用isSequential布尔值决定并行(false)/串行(true)模式。曾经在报销流程中踩过坑误将财务复核设为并行模式导致出纳同时收到多个冲突请求2.2 智能完成条件实战默认情况下多实例会等待所有任务完成。但通过completionCondition可以实现更灵活的流程控制!-- 过半通过即生效 -- completionCondition ${nrOfCompletedInstances/nrOfInstances 0.5} /completionCondition !-- 一票否决场景 -- completionCondition ${nrOfCompletedInstances 0 hasReject} /completionCondition我曾用这种机制实现过智能投票系统当赞成票达到60%时立即通过反对票超过30%时自动终止流程72小时未达成条件则进入人工仲裁3. 动态数据绑定的高阶玩法3.1 运行时数据注入在多实例场景中我经常需要将上下文数据传递给每个实例。比如在合同审批流程中需要让每个审批人看到完整的合同历史// 在流程启动前注入基础数据 runtimeService.setVariable(processInstanceId, contractHistory, getContractVersions()); // 在服务任务中动态补充审批人 public ListString getApproversWithContext(DelegateExecution execution) { Contract contract (Contract) execution.getVariable(contract); return approverDao.findByDepartment(contract.getDepartment()); }3.2 多实例与监听器的组合技通过事件监听器可以实现更精细的控制// 在每个实例创建时追加专属数据 EventListener public void onTaskCreated(DelegateTask task) { if (task.getProcessDefinitionId().contains(multiInstance)) { String approver (String) task.getVariable(approver); task.setVariableLocal(approverHistory, getApprovalHistory(approver)); } }这种模式特别适合需要审计追踪的场景。最近一个银行客户的项目中我们用它实现了完整的审批轨迹记录每个审批步骤都自动关联了当时的系统快照。4. 避坑指南与性能优化4.1 常见问题排查在实施过程中这几个问题最常出现集合数据为空建议添加前置校验sequenceFlow idcheckApprovers sourceRefgateway targetRefmultiTask conditionExpression xsi:typetFormalExpression ${!CollectionUtils.isEmpty(approverList)} /conditionExpression /sequenceFlow变量作用域混淆注意区分流程变量与本地变量父执行实例存储nrOfInstances等全局数据子执行实例通过elementVariable访问当前元素事务边界问题并行任务数量过大时可能触发数据库锁超时4.2 性能优化建议处理过的一个生产案例当审批人超过500时流程启动耗时从200ms飙升到8秒。通过以下优化方案最终控制在1秒内分批加载改造集合获取逻辑采用分页查询public ListString getApproversChunk(DelegateExecution exec) { int chunkSize 100; int offset (int) exec.getVariable(chunkIndex) * chunkSize; return approverDao.findChunk(offset, chunkSize); }异步化处理对非强一致性的任务启用异步特性multiInstanceLoopCharacteristics isSequentialfalse flowable:asynctrue缓存集合数据避免重复查询相同数据源5. 真实案例智能工单分发系统去年为某电商平台设计的客服工单系统完美展现了多实例的实战价值业务需求根据工单类型自动匹配技能组售后、技术、投诉等每个技能组内按负载均衡分配坐席30秒无响应自动升级到组长解决方案serviceTask iddispatchTask flowable:classcom.example.TicketDispatcher multiInstanceLoopCharacteristics isSequentialfalse flowable:collection${ticketRouter.getTargetGroups(execution)} flowable:elementVariabletargetGroup completionCondition ${ticketDispatcher.hasAccepted(execution) || ticketDispatcher.timeout(execution)} /completionCondition /multiInstanceLoopCharacteristics /serviceTask关键实现点通过ticketRouter动态解析工单类型对应的技能组每个技能组并行执行坐席选择逻辑完成条件检查是否有坐席接单或超时上线后平均响应时间从原来的4分钟缩短到22秒客户满意度提升35%。这个案例充分证明合理运用多实例特性可以让死板的流程活起来。