Skip to content

Flowable 工作流引擎

一、工作流基础

什么是工作流

工作流是对业务流程的抽象与建模,通过引擎驱动流程按照预定的规则自动流转。专门的工作流框架(如 CamundaActivitiFlowable)提供了设计、执行和监控工作流的完整能力,可与 Spring Boot 等技术无缝集成。

工作流的三种分类

类型特点适用场景
内存工作流无需持久化,无状态,调用完即结束用户询价、查看商品详情等只读业务
状态机工作流持久化每个节点状态,支持自动重试支付回调、开通权益等需要补偿的业务
人工工作流在状态机基础上增加外部人工触发节点审批流、多级签核等人工参与的业务

选型建议

  • 只读、无副作用 → 内存工作流
  • 需要失败重试/补偿 → 状态机工作流
  • 需要人工审批节点 → 人工工作流(Flowable 主要解决这类场景)

工作流的价值

工作流用的好,业务可维护、业务可视化,对后来者学习和维护的成本都很低。流程清晰了,异常分支的考虑、错误节点的重试、异常节点告警、超时配置,系统就具备很强的鲁棒性。


二、Flowable 介绍

核心特性

Flowable 由 Activiti 项目分支演变而来,是一个用 Java 编写的轻量级、开源 BPM(业务流程管理)引擎

  • 基于 BPMN 2.0 国际标准,非技术人员也能参与流程设计
  • JAR 包形式嵌入,支持 Java SE、Tomcat、Spring Boot、JBoss 等所有 Java 环境
  • 内置流程设计器(Flowable Modeler / Flowable UI)

版本要求

Flowable 7.x 基于 JDK 17,集成 Spring Boot 时需要 Spring Boot 3.x 及以上版本。

如果项目是 Spring Boot 2.x,请使用 Flowable 6.x 版本。

资源链接
官方文档https://www.flowable.com/open-source/docs/oss-introduction
中文文档https://tkjohn.github.io/flowable-userguide/
英文文档https://www.flowable.org/docs/userguide/index.html

BPMN 2.0 协议

BPMN 2.0(Business Process Model and Notation 2.0,业务流程模型和符号)是业务流程建模的国际标准,定义了一套图形化符号体系。

理解 BPMN 2.0 的核心元素是使用 Flowable 的前提:

元素类型常见元素说明
事件(Event)开始事件、结束事件、中间事件触发流程的起点、流程的终点、流程中的信号
任务(Task)用户任务、服务任务、脚本任务流程中具体的工作单元
网关(Gateway)排他网关、并行网关、包容网关控制流程走向的分支与汇聚节点
连线(Flow)顺序流、消息流连接各节点,定义流转方向和条件
泳道(Lane)池、道区分不同参与者/部门的责任边界

常用网关对比:

网关类型符号特征行为
排他网关(XOR)菱形 + X只走满足条件的一条分支
并行网关(AND)菱形 + +所有分支同时执行,全部完成后汇聚
包容网关(OR)菱形 + O走满足条件的一条或多条分支

三、后端搭建(Spring Boot + MySQL)

1. 添加依赖

xml
<!-- Flowable 核心依赖 -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter-process</artifactId>
    <version>6.7.1</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.29</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
xml
<!-- Flowable 7 需要 Spring Boot 3 + JDK 17 -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter-process</artifactId>
    <version>7.0.0</version>
</dependency>

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

2. 配置文件

yaml
server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flowable_demo?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: your_password   # 生产环境请使用环境变量或配置中心管理密码
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update        # 开发环境可用 update,生产环境建议 validate
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect

flowable:
  # true:启动时自动检测并创建/更新 Flowable 所需的数据库表
  # 生产环境建议设为 false,改用 Liquibase/Flyway 管理
  database-schema-update: true
  database-type: mysql

安全提示

  • 数据库密码不要硬编码在配置文件中,推荐使用 Spring 的 ${DB_PASSWORD} 引用环境变量
  • ddl-auto: updatedatabase-schema-update: true生产环境中需谨慎,自动更新表结构可能影响现有数据

3. 手动初始化数据库表(可选)

通常配置 database-schema-update: true 后启动应用会自动建表。如需手动初始化:

java
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;

// 手动创建 ProcessEngine,Flowable 会自动在数据库中建表
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
    .setJdbcUrl("jdbc:mysql://localhost:3306/flowable_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2b8&nullCatalogMeansCurrent=true")
    .setJdbcUsername("root")
    .setJdbcPassword("your_password")
    .setJdbcDriver("com.mysql.cj.jdbc.Driver")   // MySQL 8+ 使用 cj 驱动
    .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

ProcessEngine processEngine = cfg.buildProcessEngine();

四、Flowable Modeler 设计器搭建(前端)

方式一:Spring Boot 内嵌(Flowable 6.x)

1. 依赖

xml
<properties>
    <flowable.version>6.7.1</flowable.version>
</properties>

<!-- Flowable 全家桶 starter -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter</artifactId>
    <version>${flowable.version}</version>
</dependency>

<!-- IDM:身份认证模块(提供登录) -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter-ui-idm</artifactId>
    <version>${flowable.version}</version>
</dependency>

<!-- Modeler:流程图设计器 -->
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter-ui-modeler</artifactId>
    <version>${flowable.version}</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.29</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2. 配置

yaml
server:
  port: 8888

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flowable_demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    open-in-view: true

flowable:
  idm:
    app:
      admin:
        user-id: admin        # 设计器登录账号
        password: admin       # 设计器登录密码
        first-name: Admin
        last-name: User

3. 启动后访问

http://localhost:8888/

方式二:Docker 部署 Flowable UI(推荐)

bash
docker run -d \
  --name flowable-ui \
  -p 8080:8080 \
  -e SPRING_DATASOURCE_URL="jdbc:mysql://host:3306/flowable?useSSL=false&characterEncoding=UTF-8" \
  -e SPRING_DATASOURCE_USERNAME=root \
  -e SPRING_DATASOURCE_PASSWORD=your_password \
  flowable/flowable-ui

访问 http://localhost:8080/flowable-ui,默认账号密码均为 admin

TIP

Docker 方式无需修改项目代码,设计器与后端服务完全解耦,适合团队协作使用。


五、数据库表结构详解

Flowable 启动后会在数据库中自动创建约 50+ 张表,按前缀分为以下几组:

ACT_GE_* 通用表

表名说明
ACT_GE_PROPERTY存储引擎全局属性,如版本信息
ACT_GE_BYTEARRAY存储二进制数据:BPMN XML 文件、流程图图片、变量等

ACT_RE_* 流程定义表(Repository)

表名说明
ACT_RE_DEPLOYMENT部署记录:部署时间、名称,一次部署可包含多个流程定义
ACT_RE_PROCDEF流程定义元数据:标识、名称、版本号
ACT_RE_MODELFlowable Modeler 中创建的流程模型(未部署的草稿)

ACT_RU_* 运行时表(Runtime)

流程运行期间产生的数据,流程结束后自动清除

流程实例相关:

表名说明
ACT_RU_EXECUTION正在执行的流程实例和执行路径
ACT_RU_VARIABLE运行时流程变量(字符串、数值、二进制对象等)
ACT_RU_IDENTITYLINK流程实例/任务的参与者信息(候选人、负责人等)
ACT_RU_EVENT_SUBSCR事件订阅信息(等待外部事件触发)

任务相关:

表名说明
ACT_RU_TASK当前待处理的用户任务

Job 相关:

表名说明
ACT_RU_JOB等待/延迟执行的作业(异步任务、定时器)
ACT_RU_TIMER_JOB定时器任务,到达触发时间后执行
ACT_RU_DEADLETTER_JOB执行失败、无法重试的死信任务,需人工处理
ACT_RU_SUSPENDED_JOB被挂起的作业

ACT_HI_* 历史表(History)

记录已完成的流程数据,永久保留(除非手动清理)。

表名说明
ACT_HI_PROCINST已完成流程实例:开始/结束时间、持续时长
ACT_HI_ACTINST流程中每个活动节点的执行历史
ACT_HI_TASKINST已完成任务的历史:开始/结束时间、分配用户
ACT_HI_VARINST流程变量的历史快照
ACT_HI_IDENTITYLINK任务/流程实例参与者的历史记录
ACT_HI_DETAIL变量变化的详细历史记录
ACT_HI_COMMENT流程/任务的历史评论
ACT_HI_ATTACHMENT流程/任务的历史附件

其他表

表名说明
ACT_EVT_LOG引擎事件日志
ACT_PROCDEF_INFO流程定义的额外元数据

表前缀速记

前缀含义生命周期
GEGeneral 通用持久
RERepository 定义持久
RURuntime 运行时流程结束后删除
HIHistory 历史永久保留

六、SpringBoot 3 + Flowable 7 完整示例

参考:https://blog.csdn.net/qq_41892775/article/details/141108020

环境要求

组件版本要求
JDK17+
Spring Boot3.x
Flowable7.x
MySQL8.x

核心 API 速查

Flowable 的服务层由多个 Service 组成,注入后即可使用:

Service职责
RepositoryService管理流程定义:部署、查询、挂起/激活
RuntimeService管理流程实例:启动、查询、删除、设置变量
TaskService管理用户任务:查询、认领、完成、委派
HistoryService查询历史数据:已完成的实例、任务、变量
ManagementService管理引擎内部:Job 管理、表数据查询
IdentityService管理用户和组

典型流程示例

请假审批流为例,展示完整的流程生命周期:

1. 部署流程定义

java
@Autowired
private RepositoryService repositoryService;

public void deployProcess() {
    repositoryService.createDeployment()
        .name("请假审批流程")
        .addClasspathResource("processes/leave-approval.bpmn20.xml")
        .deploy();
    System.out.println("流程部署成功");
}

2. 启动流程实例

java
@Autowired
private RuntimeService runtimeService;

public void startProcess(String applicant, int days) {
    Map<String, Object> variables = new HashMap<>();
    variables.put("applicant", applicant);   // 申请人
    variables.put("days", days);             // 请假天数

    ProcessInstance instance = runtimeService
        .startProcessInstanceByKey("leaveApproval", variables);

    System.out.println("流程启动,实例ID:" + instance.getId());
}

3. 查询并完成用户任务

java
@Autowired
private TaskService taskService;

// 查询指定用户的待办任务
public List<Task> queryTasks(String assignee) {
    return taskService.createTaskQuery()
        .taskAssignee(assignee)
        .orderByTaskCreateTime().desc()
        .list();
}

// 审批通过
public void approveTask(String taskId, boolean approved) {
    Map<String, Object> variables = new HashMap<>();
    variables.put("approved", approved);
    taskService.complete(taskId, variables);
    System.out.println("任务完成,taskId:" + taskId);
}

4. 查询历史记录

java
@Autowired
private HistoryService historyService;

public void queryHistory(String processInstanceId) {
    HistoricProcessInstance history = historyService
        .createHistoricProcessInstanceQuery()
        .processInstanceId(processInstanceId)
        .singleResult();

    System.out.println("开始时间:" + history.getStartTime());
    System.out.println("结束时间:" + history.getEndTime());
    System.out.println("持续时长:" + history.getDurationInMillis() + "ms");
}

BPMN 流程文件示例

将以下文件放入 src/main/resources/processes/ 目录:

xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:flowable="http://flowable.org/bpmn"
             targetNamespace="http://flowable.org/bpmn">

  <process id="leaveApproval" name="请假审批流程" isExecutable="true">

    <!-- 开始事件 -->
    <startEvent id="start" name="开始"/>

    <!-- 申请人提交申请(用户任务) -->
    <userTask id="submitTask" name="提交申请"
              flowable:assignee="${applicant}"/>

    <!-- 经理审批(用户任务) -->
    <userTask id="approveTask" name="经理审批"
              flowable:assignee="manager"/>

    <!-- 排他网关:判断是否审批通过 -->
    <exclusiveGateway id="approveGateway" name="审批结果"/>

    <!-- 结束事件(审批通过) -->
    <endEvent id="endApproved" name="审批通过"/>

    <!-- 结束事件(审批拒绝) -->
    <endEvent id="endRejected" name="审批拒绝"/>

    <!-- 连线 -->
    <sequenceFlow sourceRef="start"          targetRef="submitTask"/>
    <sequenceFlow sourceRef="submitTask"     targetRef="approveTask"/>
    <sequenceFlow sourceRef="approveTask"    targetRef="approveGateway"/>
    <sequenceFlow sourceRef="approveGateway" targetRef="endApproved"
                  name="通过">
      <conditionExpression>${approved == true}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow sourceRef="approveGateway" targetRef="endRejected"
                  name="拒绝">
      <conditionExpression>${approved == false}</conditionExpression>
    </sequenceFlow>

  </process>
</definitions>