别再手动循环了!Flowable多实例任务实战:用Spring Boot + MySQL搞定批量审批流
Flowable多实例任务Spring Boot审批流程
于 2026-05-29 11:24:37 修改 ·本内容遵循CC 4.0 BY-SA版权协议
告别循环代码:Flowable多实例任务在Spring Boot中的高效实践
当你在处理"部门全员会签"或"多领导并行审批"这类需求时,是否还在用for循环逐个创建审批任务?上周我接手了一个采购审批系统改造项目,原代码中密密麻麻的循环和状态判断让我意识到——是时候引入Flowable的多实例特性了。本文将带你用Spring Boot和MySQL实现一个真实的批量审批流程,彻底摆脱手动循环的繁琐。
1. 为什么选择多实例替代循环逻辑
去年我们团队重构了一个存在三年的报销审批系统,原系统用传统循环处理部门会签,代码中充斥着for循环和if-else判断。当需要增加"超过半数同意即通过"的业务规则时,开发人员不得不修改多处状态判断逻辑。而采用Flowable多实例后,同样的需求只需在BPMN配置中添加一行completionCondition表达式。
多实例任务与传统循环对比:
| 特性 |
手动循环实现 |
Flowable多实例 |
| 审批进度可视化 |
需额外开发状态跟踪逻辑 |
内置nrOfCompletedInstances变量 |
| 动态调整参与者 |
修改代码重新部署 |
调整collection变量实时生效 |
| 审批规则变更 |
需重写判断逻辑 |
修改BPMN配置无需停机 |
| 历史记录完整性 |
需手动记录每个实例 |
引擎自动维护执行轨迹 |
在采购审批场景中,多实例尤其适合以下情况:
- 并行会签:需要多个部门同时审批采购申请
- 动态参与者:审批人列表来自运行时变量(如根据采购类型决定)
- 灵活完成条件:如"3人中有2人同意即可通过"
JAVA
2
public void createApprovalTasks(List<String> auditors) {
3
for (String auditor : auditors) {
4
Task task = new Task();
5
task.setAssignee(auditor);
6
task.setStatus("PENDING");
8
taskRepository.save(task);
2. Spring Boot环境快速集成
从零开始搭建一个支持多实例的运行环境比想象中简单。我习惯用MySQL作为流程数据存储,它的事务特性对流程一致性很重要。以下是关键依赖:
XML
3
<groupId>org.flowable</groupId>
4
<artifactId>flowable-spring-boot-starter</artifactId>
5
<version>6.7.2</version>
8
<groupId>mysql</groupId>
9
<artifactId>mysql-connector-java</artifactId>
10
<scope>runtime</scope>
在application.yml中配置数据库和异步执行器(多实例并行审批的关键):
YAML
2
async-executor-activate: true
3
database-schema-update: true
7
url: jdbc:mysql://localhost:3306/flowable_db?useSSL=false
注意:生产环境务必开启async-executor-activate,这是并行多实例能真正并发执行的核心配置。曾有个项目因为漏配这项,导致"并行"审批变成了队列等待。
3. 采购审批多实例实战
假设我们要实现这样一个场景:采购申请超过5万元时需要财务部、法务部、技术部三个部门并行会签,任意两个部门同意即可通过。以下是完整的实现步骤。
3.1 定义多实例BPMN模型
在resources/processes目录下创建purchase_approval.bpmn:
XML
1
<process id="purchase_approval" name="采购审批流程">
2
<startEvent id="start"/>
3
<userTask id="department_approval" name="部门会签">
4
<multiInstanceLoopCharacteristics
6
flowable:collection="${approvalDepartments}"
7
flowable:elementVariable="department">
9
${nrOfCompletedInstances >= 2}
10
</completionCondition>
11
</multiInstanceLoopCharacteristics>
13
<sequenceFlow sourceRef="department_approval" targetRef="end"/>
关键配置解析:
isSequential="false":开启并行模式
collection:使用动态部门列表变量
completionCondition:自定义完成条件
3.2 实现动态参与者逻辑
在服务层注入运行时变量。这里演示从数据库获取审批部门:
JAVA
2
public class PurchaseApprovalService {
5
private RuntimeService runtimeService;
7
public void startApprovalProcess(Long purchaseId) {
8
Map<String, Object> variables = new HashMap<>();
9
variables.put("approvalDepartments", getApprovalDepartments(purchaseId));
11
runtimeService.startProcessInstanceByKey(
13
purchaseId.toString(),
18
private List<String> getApprovalDepartments(Long purchaseId) {
19
Purchase purchase = purchaseRepository.findById(purchaseId);
20
if (purchase.getAmount() > 50000) {
21
return Arrays.asList("finance", "legal", "tech");
23
return Collections.singletonList("finance");
3.3 处理多实例任务
创建Controller处理审批操作:
JAVA
2
@RequestMapping("/approval")
3
public class ApprovalController {
5
@PostMapping("/complete/{taskId}")
6
public String completeTask(@PathVariable String taskId,
7
@RequestParam boolean approved) {
8
Task task = taskService.createTaskQuery()
12
Map<String, Object> variables = new HashMap<>();
13
variables.put("approved_" + task.getVariable("department"), approved);
15
taskService.complete(taskId, variables);
实用技巧:在变量名前加上部门前缀(如approved_finance),方便在网关判断时区分不同部门的审批结果。
4. 多实例开发中的避坑指南
在三个实际项目中使用多实例后,我总结了这些容易踩坑的场景:
4.1 变量作用域问题
多实例任务中的变量分为两种:
- 实例级变量:通过
elementVariable定义,每个实例独立
- 流程级变量:通过
runtimeService.setVariable设置,全局可见
常见错误是在子实例中误改流程变量。正确做法:
JAVA
2
taskService.setVariable(taskId, "approvalResult", result);
5
taskService.setVariableLocal(taskId, "departmentResult", result);
4.2 事务边界控制
当多实例任务与业务操作混合时,注意事务划分:
JAVA
2
public void approvePurchase(String taskId, ApprovalDTO dto) {
4
taskService.complete(taskId, dto.getVars());
7
purchaseService.updateStatus(dto.getPurchaseId());
4.3 性能优化建议
处理大规模并行审批时(如超过50个实例):
- 调整
flowable.async-executor.core-pool-size(默认8)
- 避免在
collection表达式中执行耗时查询
- 对固定参与者列表使用缓存
5. 进阶:动态调整运行中的多实例
上周遇到个需求:采购申请金额变更后,需要动态增减审批部门。通过API可以实时修改运行中的多实例��
JAVA
1
public void adjustApprovers(String processInstanceId, List<String> newDepartments) {
2
Execution execution = runtimeService.createExecutionQuery()
3
.processInstanceId(processInstanceId)
4
.activityId("department_approval")
7
runtimeService.setVariable(
13
runtimeService.addMultiInstanceExecution(
14
"department_approval",
这个方案比重新发起流程更符合业务实际,但要注意:
- 新增的实例会立即开始并行执行
- 已完成的实例不受影响
- 总实例数变化会自动更新
nrOfInstances