Flowable 是一个功能完备的开源工作流引擎,源自 Activiti 的分支发展而来,完全兼容 BPMN 2.0 规范。它既能以独立服务的方式运行,也可以作为 jar 包直接嵌入 Spring Boot 应用中,对国内大量基于 Spring 技术栈的中小企业系统来说,嵌入式方案部署简单、运维成本低,是最常见的选择。本文将以一个典型的请假审批流程为例,完整演示 Spring Boot 整合 Flowable 的全过程,包括环境搭建、流程图绘制、部署、审批流转以及历史查询等核心环节。

一、环境准备与依赖配置
整合 Flowable 的第一步是引入官方提供的 starter。Flowable 针对 Spring Boot 提供了 flowable-spring-boot-starter-process,它内部已经做好了自动装配,只要类路径存在该依赖,引擎就会随应用一起启动。在 pom.xml 中添加如下配置:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-process</artifactId>
<version>6.8.0</version>
</dependency>Flowable 启动时需要数据库存储流程定义、任务、历史记录等数据。它默认支持 MySQL、PostgreSQL、Oracle 等主流数据库,所有表以 ACT_ 前缀命名,例如 ACT_RE_DEPLOYMENT 存放部署信息,ACT_RU_TASK 存放运行时任务,ACT_HI_TASKINST 存放历史任务。在 application.yml 中配置数据源即可,首次启动时 Flowable 会自动建表:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/flowable_demo?nullCatalogMeansCurrent=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
flowable:
# 首次启动自动建表,后续建议改为 false 提升启动速度
database-schema-update: true
async-executor-activate: false这里有一个 MySQL 8 的常见坑需要注意:nullCatalogMeansCurrent=true 这个参数必须加上,否则 Flowable 在校验表结构时可能扫描到其他库的同名表,直接抛出异常导致启动失败。另外建议在生产环境把 database-schema-update 关掉,由 DBA 统一执行官方提供的 SQL 脚本来管理表结构,避免应用账号拥有 DDL 权限带来安全隐患。
二、设计并部署一个请假审批流程
流程设计推荐使用 Flowable 官方的 Flowable Modeling 模块,也可以直接在 IDEA 中安装 Flowable Designer 插件。一个最简的请假流程包含:开始节点、申请人提交任务、组长审批、条件网关(判断请假天数)、经理审批、结束节点。下面是对应的 BPMN XML 核心片段:
<process id="leaveProcess" name="请假审批流程">
<startEvent id="start"/>
<userTask id="applyTask" name="提交申请" flowable:assignee="${applyUser}"/>
<userTask id="leaderAudit" name="组长审批" flowable:assignee="${leader}"/>
<exclusiveGateway id="dayGateway"/>
<userTask id="managerAudit" name="经理审批" flowable:assignee="${manager}"/>
<sequenceFlow id="flow1" sourceRef="leaderAudit" targetRef="dayGateway"/>
<sequenceFlow id="flow2" sourceRef="dayGateway" targetRef="managerAudit">
<conditionExpression xsi:type="tFormalExpression">
${days > 3}
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow3" sourceRef="dayGateway" targetRef="end"/>
</process>流程文件编写好后,最简单的部署方式是把它放到 src/main/resources/processes 目录下,Spring Boot 集成模块会自动扫描该目录并完成部署。也可以通过 RepositoryService 手动部署,适合流程图存在数据库或文件服务器上的场景:
@Service
public class ProcessDeployService {
@Autowired
private RepositoryService repositoryService;
public String deploy() {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("processes/leave.bpmn20.xml")
.name("请假流程")
.deploy();
return deployment.getId();
}
}需要理解的一个重要概念是:流程定义(ProcessDefinition)和流程实例(ProcessInstance)是一对多的关系。每修改一次流程图并重新部署,就会生成一个新版本的流程定义,版本号自动加一;而每次发起审批,都会基于某个版本创建一条流程实例。旧的实例继续按旧版本流转,新的实例走新版本,这正是 BPMN 引擎版本化机制带来的好处。
三、发起流程与审批流转的实现
发起流程使用 RuntimeService,传入流程定义的 key 和流程变量。流程变量在整个实例生命周期内全局可见,网关条件、任务分配表达式都会用到它们:
@RestController
@RequestMapping("/leave")
public class LeaveController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
// 发起请假申请
@PostMapping("/start")
public String start(String applyUser, String leader, int days) {
Map<String, Object> vars = new HashMap<>();
vars.put("applyUser", applyUser);
vars.put("leader", leader);
vars.put("days", days);
ProcessInstance pi = runtimeService
.startProcessInstanceByKey("leaveProcess", vars);
return pi.getId();
}
// 审批通过
@PostMapping("/approve")
public void approve(String taskId, String comment) {
// 添加审批意见,便于追溯
taskService.addComment(taskId, null, comment);
taskService.complete(taskId);
}
}审批人登录后需要查询自己的待办任务,这通过 TaskService 完成。待办列表一般还要关联业务表单数据,通常的做法是把业务主键作为流程变量存进去,或者利用 Flowable 的 businessKey 字段建立流程实例与业务单据的关联:
// 查询某人的待办任务
public List<Map<String, Object>> todoList(String assignee) {
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee(assignee)
.orderByTaskCreateTime().desc()
.list();
List<Map<String, Object>> result = new ArrayList<>();
for (Task task : tasks) {
Map<String, Object> item = new HashMap<>();
item.put("taskId", task.getId());
item.put("name", task.getName());
item.put("createTime", task.getCreateTime());
result.add(item);
}
return result;
}审批流转中最容易被忽略的是候选组的使用。真实企业里审批人往往是某个部门或角色,而不是固定某人。可以把 userTask 配置成 flowable:candidateGroups="deptLeader",该组的所有人都能看到这条待办,其中一人先执行 taskService.claim(taskId, userId) 认领任务,任务就会从候选人变成被指派人,避免多人同时审批造成数据混乱。
四、历史查询与常见问题处理
流程结束后,运行时数据会被删除并转入历史表,此时要使用 HistoryService 查询。通过 createHistoricProcessInstanceQuery 可以拿到整个流程的开始时间、结束时间、发起人,而 createHistoricTaskInstanceQuery 和 createHistoricActivityInstanceQuery 则能还原每个节点的处理轨迹,这是做审批日志页面的核心数据来源:
// 查询某流程实例的完整审批轨迹
public List<HistoricActivityInstance> trace(String processInstanceId) {
return historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityStartTime().asc()
.list();
}整合过程中有几个高频问题值得提前防范。第一,驳回跳转不能简单理解为往回 complete 任务,正确做法是使用 runtimeService.createChangeActivityStateBuilder() 进行节点跳转,把流程拨回到指定节点并重新生成任务。第二,网关条件表达式里引用的流程变量必须存在,否则会抛出 UnknownPropertyException,建议在发起流程前做一次变量完整性校验。第三,如果涉及定时节点或异步任务,务必开启 async-executor-activate: true,否则定时边界事件不会触发。第四,业务数据和流程数据的事务一致性要靠把业务表的更新和 Flowable 的 API 调用放在同一个 Spring 事务方法内完成,Flowable 会自动注册同步器,任一环节异常时整体回滚。
整体来看,Flowable 与 Spring Boot 的整合成本并不高,难点在于把业务模型和流程模型设计好。掌握流程定义、实例、任务、变量这四者关系之后,再加上网关、多实例会签、边界事件等进阶特性,就能支撑起绝大多数企业内部审批场景的落地。
Spring BootFlowable工作流引擎修改时间:2026-09-11 08:42:46