Flowable 工作流引擎入门教程(基础篇):从零跑通一个请假流程
Flowable 工作流引擎入门教程(基础篇)
本文基于 Flowable 官方用户手册(flowable-userguide)与邓澎波老师的 Flowable 课件系统整理,目标是让没有工作流基础的开发者也能在半小时内跑通第一个完整的请假审批流程。
企业里的「请假」「报销」「采购」本质上都是流程:有起点、有审批节点、有分支判断、有终点。把这些流程用代码硬编码,短期内能跑,长期必然陷入改不动的泥潭。Flowable 就是为解决这类问题而生的轻量级工作流引擎。
一、Flowable 是什么
Flowable 是 BPMN 2.0 规范的一个基于 Java 的开源实现。但它不止于 BPMN——还包含:
- BPMN:业务流程建模与执行(最常用的部分)
- DMN:决策表引擎(规则判断)
- CMMN:Case 管理引擎(非结构化的、事件驱动型流程)
- 自带的用户管理与微服务 API
换句话说,Flowable 不只是一个「流程库」,而是一整套「业务流程服务平台」。
二、环境准备:构建 ProcessEngine
创建一个普通的 Maven 工程,引入两个核心依赖:Flowable 流程引擎 + MySQL 驱动。
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
ProcessEngine 是线程安全的对象,整个应用通常只需初始化一次。它由 ProcessEngineConfiguration 创建,最小配置只需要 JDBC 连接信息:
public static void main(String[] args) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
}
MySQL 8 的一个坑
在 MySQL 8.0 下直接用上面的连接串,可能出现「找不到表 / 建表失败」的报错。原因是 MySQL 8 的 JDBC 驱动默认会扫描所有库。只需在连接串里加上 nullCatalogMeansCurrent=true,让它只查当前库:
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC&nullCatalogMeansCurrent=true")
配置日志(SLF4J + Log4j)
引擎启动后如果控制台只有一行「日志未正确配置」的提示,说明缺日志实现。Flowable 内部用 SLF4J,这里用 Log4j 作为实现:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
在 src/main/resources 下新建 log4j.properties:
log4j.rootLogger=DEBUG, CA
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern=%d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
再次运行,buildProcessEngine() 会自动创建约 60 张以 ACT_ 开头的表(如 ACT_RE_* 流程定义、ACT_RU_* 运行时、ACT_HI_* 历史)。至此,一个可用的流程引擎就起来了。
三、流程定义:BPMN 2.0
我们以最简单的「请假流程」为例:员工提交申请 → 经理审批 → 排他网关判断通过/驳回 → 通过则归档并通知,驳回则邮件通知。
BPMN 2.0 用 XML 描述流程,同时包含可视化信息。下面是一个最小可运行的 holiday-request.bpmn20.xml:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="holidayRequest" name="请假流程" isExecutable="true">
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<userTask id="approveTask" name="经理审批" flowable:assignee="manager"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved == true}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="rejectNotify">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved == false}]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="externalSystemCall" name="归档到外部系统"
flowable:class="org.flowable.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="approveNotify"/>
<userTask id="approveNotify" name="通知申请人(通过)" flowable:assignee="applicant"/>
<sequenceFlow sourceRef="approveNotify" targetRef="endEvent"/>
<userTask id="rejectNotify" name="通知申请人(驳回)" flowable:assignee="applicant"/>
<sequenceFlow sourceRef="rejectNotify" targetRef="endEvent"/>
<endEvent id="endEvent"/>
</process>
</definitions>
把这段 XML 保存到 src/main/resources/holiday-request.bpmn20.xml。
流程里的几个核心元素务必记住:
- 启动事件(start event):流程实例的起点(左侧圆圈)。
- 用户任务(user task):需要人处理的节点,比如「经理审批」。
- 排他网关(exclusive gateway):带叉的菱形,根据条件把流程路由到不同分支。
- 服务任务(service task):自动调用 Java 类 / 外部系统的节点。
BPMN 2.0 的妙处在于:技术人员和业务人员看的是同一套图形符号,沟通成本大幅下降。
四、部署流程定义
部署就是把 BPMN 文件交给引擎管理,存进数据库。通过 RepositoryService 完成:
@Test
public void testDeploy() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.name("请假流程")
.category("请假")
.tenantId("dpb")
.deploy();
System.out.println("deploy.getId() = " + deploy.getId());
System.out.println("deploy.getName() = " + deploy.getName());
}
部署会往几张关键表里写数据:
| 表名 | 作用 |
|---|---|
ACT_GE_BYTEARRAY |
部署的二进制资源(BPMN XML、图片) |
ACT_RE_DEPLOYMENT |
部署记录(名称、时间、租户) |
ACT_RE_PROCDEF |
解析后的流程定义(key、版本号、所属部署) |
注意:每次部署同一
process id会生成新的版本,Flowable 用key + version区分,老版本的实例仍按老定义跑完,不会互相干扰。
五、启动流程实例
流程定义是「蓝图」,流程实例是「一次真实的请假申请」。通过 RuntimeService 启动:
@Test
public void testStart() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put("employee", "张三");
variables.put("days", 3);
variables.put("reason", "回家探亲");
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("holidayRequest", variables);
System.out.println("流程实例ID:" + instance.getId());
System.out.println("当前活动节点:" + instance.getActivityId());
}
启动后,流程会停在第一个用户任务「经理审批」。可以在 ACT_RU_TASK 表里看到这条待办。
六、查询与完成任务
经理登录系统后,查询自己的待办并审批:
@Test
public void testComplete() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 查询 manager 的待办
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee("manager")
.processDefinitionKey("holidayRequest")
.list();
for (Task task : tasks) {
System.out.println("待办:" + task.getName() + " id=" + task.getId());
}
// 审批通过,传入网关判断变量
Task task = tasks.get(0);
Map<String, Object> result = new HashMap<>();
result.put("approved", true);
taskService.complete(task.getId(), result);
}
complete 时传入的 approved=true 会被排他网关使用,流程路由到「归档 + 通知」分支,最终到达结束事件。
七、七大核心 Service 总览
ProcessEngine 通过不同的 Service 暴露能力,记住这张表就掌握了 Flowable 的骨架:
| Service | 职责 |
|---|---|
RepositoryService |
资源管理:部署流程、查询流程定义、挂起/激活 |
RuntimeService |
运行时管理:启动/查询流程实例、流程变量 |
TaskService |
任务管理:查询/认领/完成用户任务 |
HistoryService |
历史管理:查询已完成的实例、任务、变量 |
ManagementService |
引擎运维:数据库维护、定时作业管理 |
IdentityService |
用户与组管理(认证相关) |
FormService |
表单数据(可选,常与外部表单系统配合) |
小知识:
RepositoryService/RuntimeService等最早在 Activiti 中叫「资源管理类 / 流程运行管理类」,二者同宗——Flowable 正是从 Activiti 6 分支出来的。
八、BPMN 常用图标速查
| 类型 | 常见图标 | 含义 |
|---|---|---|
| 事件 | ● 圆圈 | 启动事件、边界事件、中间事件、结束事件 |
| 活动/任务 | □ 圆角矩形 | 用户任务、服务任务、子流程 |
| 网关 | ◇ 菱形 | 排他、并行、包容网关(做决策) |
| 结构 | 大框 | 子流程、池/泳道 |
掌握这四类符号,基本能读懂 90% 的业务流程图。
九、小结与进阶
本篇我们完成了:
- 搭建 Flowable + MySQL 环境(含 MySQL 8 的
nullCatalogMeansCurrent坑与日志配置); - 用 BPMN 2.0 定义了一个请假流程;
- 部署、启动实例、查询并完成任务,跑通了完整闭环;
- 认识了七大 Service 与 BPMN 核心图标。
流程变量的高级玩法、UEL 表达式分配、任务监听器、多实例、网关深入等,会在进阶篇展开。如果你只想快速验证引擎,按上面六步走即可——一个能跑的请假流程,就是工作流入门最好的老师。
参考资料
- Flowable 官方用户手册:https://tkjohn.github.io/flowable-userguide/
- 邓澎波《Flowable 工作流引擎课件》系列

浙公网安备 33010602011771号