别再只会用Assignee了!用Activiti7多实例搞定会签与或签的完整配置流程
Activiti7多实例实战:从会签到或签的进阶审批配置指南
当审批流程从单人决策转向集体决策时,工作流引擎的配置复杂度会呈指数级上升。想象这样一个场景:某跨国企业的采购申请需要经过三个区域负责人的联合审批,其中任意两位同意即可生效;或者紧急报销流程只需获得财务部门任意一位主管的批准就能进入下一环节。这类需求在Activiti7中可以通过多实例任务(Multi-Instance Task)优雅实现,但90%的中级开发者都会在Completion Condition表达式或Collection变量传递环节踩坑。
1. 多实例任务的核心架构解析
多实例任务本质上是BPMN 2.0规范中的一种特殊活动类型,它允许单个任务节点在运行时动态创建多个实例。与简单的Assignee分配不同,这种机制为复杂审批场景提供了三种关键控制维度:
执行模式选择:
- 顺序执行(Sequential=true):适用于需要层级审批的场景,如先部门经理后总监
- 并行执行(Sequential=false):适用于同级多人同时审批,如委员会投票
参与者配置矩阵:
| 配置项 | 作用域 | 示例值 | 注意事项 |
|---|---|---|---|
| Collection | 流程变量 | ${approveUserList} | 必须实现java.util.List接口 |
| Element Variable | 元素变量 | member | 与Assignee表达式保持一致 |
| Loop Cardinality | 固定数量 | 3 | 与Collection互斥 |
完成条件的三层控制体系:
- 数量阈值:
${nrOfCompletedInstances >= 2} - 比例控制:
${nrOfCompletedInstances/nrOfInstances > 0.6} - 自定义逻辑:通过DelegateExecution注入业务判断
// Spring Boot中的多实例流程启动示例 @RestController @RequestMapping("/process") public class MultiInstanceController { @Autowired private RuntimeService runtimeService; @PostMapping("/start") public String startProcess(@RequestBody ApproveRequest request) { Map<String, Object> variables = new HashMap<>(); variables.put("approveUserList", request.getApprovers()); variables.put("minApproves", request.getMinApproves()); ProcessInstance instance = runtimeService.startProcessInstanceByKey( "multiInstanceProcess", variables ); return instance.getId(); } }2. 会签模式的深度配置实战
会签(即"与签")是多人必须全部或部分完成审批才能使流程继续的典型场景。某电商平台的退款审核系统曾因错误配置导致2000多笔订单卡在审批环节,根本原因正是Completion Condition表达式与业务规则不匹配。
比例通过型会签的黄金配置法则:
- 在BPMN设计器中设置Multi-Instance类型为Parallel
- Collection填写流程变量名如
${approveUserList} - Completion Condition填入比例公式:
${nrOfCompletedInstances/nrOfInstances >= 0.7}
动态阈值实现方案:
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${approveUserList}" activiti:elementVariable="approver"> <completionCondition>${nrOfCompletedInstances >= minApproves}</completionCondition> </multiInstanceLoopCharacteristics>审批结果聚合的三种模式对比:
乐观模式(任一通过):
# 历史任务记录示例 SELECT * FROM act_hi_taskinst WHERE PROC_INST_ID_ = '1001' AND DELETE_REASON_ IS NULL;悲观模式(全员通过):
// 在DelegateTask中校验历史审批结果 List<HistoricTaskInstance> histories = historyService .createHistoricTaskInstanceQuery() .processInstanceId(execution.getProcessInstanceId()) .list(); long rejects = histories.stream() .filter(h -> "REJECT".equals(h.getVariable("result"))) .count(); if(rejects > 0) { execution.setVariable("approved", false); }混合模式(自定义规则):
-- 数据库级别验证(Oracle示例) SELECT SUM(CASE WHEN VAR_TEXT_ = 'APPROVE' THEN 1 ELSE 0 END) approves, COUNT(*) total FROM ACT_HI_VARINST WHERE PROC_INST_ID_ = '1001' AND NAME_ = 'approvalResult'
3. 或签模式的特殊处理技巧
或签(即"或签")的特点是任一处理人完成操作即可推动流程,但实际业务中往往需要区分"通过"和"拒绝"两种操作结果。某金融机构的贷款审批系统就曾因未处理拒绝场景导致错误放款。
基础或签配置:
Completion Condition: ${nrOfCompletedInstances >= 1}增强型或签实现方案:
在任务完成时注入决策结果:
taskService.complete(taskId, Variables.putValue("decision", "REJECT") );配置边界事件捕获拒绝:
<boundaryEvent id="rejectEvent" attachedToRef="approvalTask"> <messageEventDefinition messageRef="rejectMsg" /> </boundaryEvent>使用执行监听器清理残余实例:
public class CancelInstancesListener implements ExecutionListener { @Override public void notify(DelegateExecution execution) { runtimeService.createExecutionQuery() .activityId("approvalTask") .list() .forEach(e -> runtimeService.deleteExecution(e.getId())); } }
或签场景下的数据一致性挑战:
- ACT_RU_TASK表:未完成任务需手动清理
- ACT_HI_TASKINST表:通过
DELETE_REASON_字段区分自然完成与强制终止 - 业务数据同步:建议采用SAGA模式补偿事务
4. 生产环境中的性能优化策略
当审批人员规模超过50人时,原生多实例实现可能遇到性能瓶颈。某政务审批平台在接入300+部门时,流程实例启动时间达到了不可接受的8秒。
索引优化方案:
-- MySQL性能优化示例 ALTER TABLE ACT_RU_IDENTITYLINK ADD INDEX idx_task_assignee (TASK_ID_, TYPE_, USER_ID_); ALTER TABLE ACT_RU_VARIABLE ADD INDEX idx_proc_inst_name (PROC_INST_ID_, NAME_);批量处理模式:
// 使用Bulk API处理大规模审批人 List<String> approvers = getHugeApproverList(); // 500+人 runtimeService.createProcessInstanceBuilder() .processDefinitionKey("massApproval") .variable("approveUserList", approvers) .variable("batchSize", 100) .addExtensionElement(new BatchConfigElement()) .executeAsync();缓存层设计要点:
使用Redis缓存流程定义:
# application.yml配置 activiti: process-definition-cache: enabled: true max-size: 1000 expire-after-write: 1h审批人列表分片加载:
@Cacheable(value = "approvers", key = "#deptId") public List<String> getDepartmentApprovers(String deptId) { // 数据库查询 }历史决策结果预加载:
/* MyBatis映射示例 */ <select id="getApprovalTrend" resultType="ApprovalStat"> SELECT APPROVER, COUNT(*) total FROM BIZ_APPROVAL_HISTORY WHERE PROCESS_DEF_ID = #{defId} GROUP BY APPROVER </select>
在大型制造业集团的采购系统中,通过组合使用这些优化策略,成功将200人规模的会签流程实例启动时间从12秒降低到1.8秒,任务分配耗时从5秒降至400毫秒。关键点在于:提前识别Collection变量的数据规模,对超百人场景采用分批加载机制;对高频使用的流程定义启用二级缓存;在历史数据查询上建立适当的索引策略。
