🧩 工作流 Workflow —— 将复杂业务流程自动化的强大引擎
在软件系统中,当我们需要管理对象的状态变化时,状态机是一种十分有效的建模方式:它把“状态 + 事件 → 新状态”的规则写得清清楚楚,让大量 if-else 逻辑变得可控、可维护。
但随着业务规模扩大、流程参与者增多、规则不断细化,仅靠状态机已经难以覆盖所有场景。此时,一种能够描述业务步骤、条件分支、人工审批、系统任务,并支持可视化配置的机制显得尤为重要——这就是 工作流(Workflow)。
工作流的出现,正是为了解决复杂业务流程的可视化建模、规范流转与自动执行问题。它能够让系统根据业务规则像“流水线”一样自动推进,使流程标准化、透明化与可控化。
一、为什么需要工作流?🤔
在一个公司中,随处可见这样的流程:
- 请假需要依次经过多级领导审批
- 报销/采购可能涉及预算审核、合同审核、财务支付
- 订单处理包含风控校验、库存锁定、拣货、发货、签收等步骤
- 内容审核经过自动检测、人工审核、复审、发布等环节
这些流程的共同特点是:
- 参与者多样:既有系统任务,也有人为审批
- 流程具有条件分支:根据金额、类型、权限走不同路径
- 可能存在并行执行:例如多人会签
- 涉及超时、催办、撤销 等操作
- 流程需要动态调整:不能每改一次流程就改代码、发版
如果尝试用代码硬写 if-else 或状态机来实现,不仅容易混乱、难以扩展,也不利于频繁变更。因此,一种能够 通过“图”建模流程并自动执行 的机制成为必然选择。
二、什么是工作流?🔍
工作流(Workflow) 是一种用于 描述、执行和管理业务流程 的模型与引擎。
它的目标是把业务中的每一步抽象为清晰的节点,通过规则驱动节点之间的流转,使复杂流程能够自动化、结构化地执行。
一个典型的工作流由以下元素组成:
| 要素 |
描述 |
| 节点(Node) |
流程中的一个步骤,可能是人工任务、系统任务、开始/结束节点等 |
| 流转(Flow) |
节点之间的连接关系,决定“下一步去哪” |
| 条件(Condition) |
用于判断流程分支,如“天数 > 3 走经理审批” |
| 参与者(Assignee) |
指定负责某步骤的人或角色 |
| 定时器(Timer) |
处理超时事件,如提醒或自动流转 |
| 表单与上下文(Form & Context) |
流程相关的数据载体 |
| 历史记录(History) |
用于审计与流程追踪 |
工作流的标准建模语言是 BPMN 2.0,几乎所有成熟引擎都支持,例如:
- Flowable
- Activiti
- Camunda
- 各种基于 BPMN 的企业级工作流产品
三、工作流能解决哪些状态机难以处理的需求?🆚
状态机非常适合处理“对象生命周期”,例如:
- 订单状态:
CREATED → PAID → SHIPPED → DELIVERED
- 账号状态:
NEW → ACTIVE → SUSPENDED → CLOSED
一旦需要处理以下这些需求,状态机就开始吃力:
1. 多人审批流程
- 请假、报销、采购、合同审核等
- 需要多级审批,有时还会加签、会签、转交
状态机本身不关心“谁”来操作某个状态,而工作流天然支持“参与者”这一概念。
2. 动态变化的流程
- 运营说:以后金额超过 3000 就要多加一级审批
- 法务说:合同类型 A 走流程 X,合同类型 B 走流程 Y
如果所有规则写死在代码里,一次流程变更就是一次开发+测试+发版;
而在工作流系统中,只需在流程设计器中调整图即可,无需改业务代码。
3. 并行任务
- 内容上线前需要 内容团队 与 法务团队 同时审核
- 招聘流程中背景调查与笔试可并行进行
状态机本质结构偏线性,不擅长表达“同时做两件事”;
而工作流有原生的并行网关(Parallel Gateway)来表示“并发执行”。
4. 超时处理与催办
- 48 小时内不审批自动提醒
- 7 天未处理自动驳回或升级
状态机没有时间维度,超时往往只能额外写定时任务;
工作流引擎通常直接内置定时器节点(Timer),可以在流程图中表现出来。
5. 可视化与可追踪性
业务人员不看代码,他们需要:
- 清晰的流程图
- 当前流程所处位置
- 历史审批记录
- 流程变更的版本管理
这些是工作流系统的基础能力,也是状态机难以直接提供的。
状态机非常适合处理“对象生命周期”,例如:
- 订单状态:
CREATED → PAID → SHIPPED → DELIVERED
- 账号状态:
NEW → ACTIVE → SUSPENDED → CLOSED
一旦需要处理以下这些需求,状态机就开始吃力:
1. 多人审批流程
- 请假、报销、采购、合同审核等
- 需要多级审批,有时还会加签、会签、转交
状态机本身不关心“谁”来操作某个状态,而工作流天然支持“参与者”这一概念。
2. 动态变化的流程
- 运营说:以后金额超过 3000 就要多加一级审批
- 法务说:合同类型 A 走流程 X,合同类型 B 走流程 Y
如果所有规则写死在代码里,一次流程变更就是一次开发+测试+发版;
而在工作流系统中,只需在流程设计器中调整图即可,无需改业务代码。
3. 并行任务
- 内容上线前需要 内容团队 与 法务团队 同时审核
- 招聘流程中背景调查与笔试可并行进行
状态机本质结构偏线性,不擅长表达“同时做两件事”;
而工作流有原生的并行网关(Parallel Gateway)来表示“并发执行”。
4. 超时处理与催办
- 48 小时内不审批自动提醒
- 7 天未处理自动驳回或升级
状态机没有时间维度,超时往往只能额外写定时任务;
工作流引擎通常直接内置定时器节点(Timer),可以在流程图中表现出来。
5. 可视化与可追踪性
业务人员不看代码,他们需要:
- 清晰的流程图
- 当前流程所处位置
- 历史审批记录
- 流程变更的版本管理
这些是工作流系统的基础能力,也是状态机难以直接提供的。
四、一个典型的工作流流程图示例:请假审批🌿
先看一下一个简单的请假审批流程:

可以看到,这个流程包含:
- 开始 / 结束 节点
- 用户任务(员工提交、领导审批、经理审批、HR 备案)
- 条件网关(根据请假天数选择不同路径)
在 BPMN 里,这会对应一张带多种节点的流程图:
- 圆形:开始事件 / 结束事件
- 矩形:任务节点(User Task)
- 菱形:网关(条件判断)
五、BPMN 2.0 简单示例(XML 片段)
下面是一个高度简化的 BPMN 2.0 流程定义(仅示意结构,实际项目可按引擎要求完善):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <?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" targetNamespace="http://example.com/workflow">
<process id="leave_process" name="请假流程" isExecutable="true">
<startEvent id="startEvent" name="开始"> <outgoing>flow_start_to_apply</outgoing> </startEvent>
<userTask id="task_apply" name="填写请假单" activiti:assignee="${applicant}"> <incoming>flow_start_to_apply</incoming> <outgoing>flow_apply_to_leader</outgoing> </userTask>
<userTask id="task_leader_approve" name="直属领导审批" activiti:assignee="${leader}"> <incoming>flow_apply_to_leader</incoming> <outgoing>flow_leader_to_gateway</outgoing> </userTask>
<exclusiveGateway id="gateway_days_check" name="天数判断"> <incoming>flow_leader_to_gateway</incoming> <outgoing>flow_gateway_to_manager</outgoing> <outgoing>flow_gateway_to_hr</outgoing> </exclusiveGateway>
<userTask id="task_manager_approve" name="部门经理审批" activiti:assignee="${manager}"> <incoming>flow_gateway_to_manager</incoming> <outgoing>flow_manager_to_hr</outgoing> </userTask>
<userTask id="task_hr_record" name="HR 备案" activiti:assignee="hr"> <incoming>flow_gateway_to_hr</incoming> <incoming>flow_manager_to_hr</incoming> <outgoing>flow_hr_to_end</outgoing> </userTask>
<endEvent id="endEvent" name="结束"> <incoming>flow_hr_to_end</incoming> </endEvent>
<sequenceFlow id="flow_start_to_apply" sourceRef="startEvent" targetRef="task_apply"/> <sequenceFlow id="flow_apply_to_leader" sourceRef="task_apply" targetRef="task_leader_approve"/> <sequenceFlow id="flow_leader_to_gateway" sourceRef="task_leader_approve" targetRef="gateway_days_check"/> <sequenceFlow id="flow_gateway_to_manager" sourceRef="gateway_days_check" targetRef="task_manager_approve"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${days > 3}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow_gateway_to_hr" sourceRef="gateway_days_check" targetRef="task_hr_record"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${days <= 3}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow_manager_to_hr" sourceRef="task_manager_approve" targetRef="task_hr_record"/> <sequenceFlow id="flow_hr_to_end" sourceRef="task_hr_record" targetRef="endEvent"/>
</process> </definitions>
|
实际使用时,可在流程设计器(如 Flowable Modeler)里画图,它会自动帮你生成相应的 BPMN XML。
六、Java + Flowable 工作流引擎快速接入示例 🛠
下面以 Spring Boot + Flowable 为例,演示一个极简工作流接入流程,基于上面的请假审批场景。
1.引入 Maven 依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <dependencies> <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter-process</artifactId> <version>6.8.0</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>
|
版本号可根据实际使用的 Flowable/Spring Boot 版本调整。
2.放置流程定义文件
将刚才的 leave_process 流程定义保存为 leave_process.bpmn20.xml,放到:
1
| src/main/resources/processes/leave_process.bpmn20.xml
|
Flowable 默认会扫描 resources/processes 目录并自动部署 BPMN 流程。
3.配置 application.yml(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: datasource: url: jdbc:h2:mem:flowable-db;DB_CLOSE_DELAY=-1 driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: update show-sql: true
flowable: check-process-definitions: true database-schema-update: true async-executor-activate: false
|
4.启动流程实例(发起请假)
Service 代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import org.flowable.engine.RuntimeService; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.Map;
@Service public class LeaveWorkflowService {
private final RuntimeService runtimeService;
public LeaveWorkflowService(RuntimeService runtimeService) { this.runtimeService = runtimeService; }
public String startLeaveProcess(String applicant, String leader, String manager, int days) {
Map<String, Object> vars = new HashMap<>(); vars.put("applicant", applicant); vars.put("leader", leader); vars.put("manager", manager); vars.put("days", days);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leave_process", vars);
return processInstance.getId(); } }
|
5.查询用户待办任务
假设要查询某个审批人的待办任务(比如直属领导):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import org.flowable.engine.TaskService; import org.flowable.task.api.Task; import org.springframework.stereotype.Service;
import java.util.List;
@Service public class TaskQueryService {
private final TaskService taskService;
public TaskQueryService(TaskService taskService) { this.taskService = taskService; }
public List<Task> getTodoTasks(String assignee) { return taskService.createTaskQuery() .taskAssignee(assignee) .orderByTaskCreateTime() .desc() .list(); } }
|
6.完成任务(审批通过 / 拒绝)
审批人处理任务时,只需调用 complete 即可,让流程继续往下流转:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import org.flowable.engine.TaskService; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.Map;
@Service public class ApproveService {
private final TaskService taskService;
public ApproveService(TaskService taskService) { this.taskService = taskService; }
public void approve(String taskId, boolean approved) { Map<String, Object> vars = new HashMap<>(); vars.put("approved", approved); taskService.complete(taskId, vars); } }
|
在 BPMN 流程中,可以在顺序流或网关处使用 ${approved} 条件表达式, 决定接下来是“流程继续”还是“流程结束/驳回”。
七、工作流与状态机的关系:互补,而非替代🌉
总结一下两者的核心区别与配合方式:
| 维度 |
状态机 |
工作流 |
| 关注点 |
对象状态变化 |
业务流程流转 |
| 适用场景 |
生命周期管理,如订单状态 |
人机协作、审批、复杂编排 |
| 可视化 |
较弱 |
强(BPMN 流程图) |
| 动态变更 |
一般需要改代码 |
通常改流程图即可 |
| 是否包含参与者概念 |
通常没有 |
原生支持 |
一个成熟系统往往会 同时使用两者:
- 用状态机控制实体的“状态是否合法变化”
- 用工作流编排“围绕该实体的完整业务流程”
八、结语🧠
工作流的本质不是为了“炫技”,而是把复杂、混乱、隐性的业务流程,沉淀为清晰、可视、可维护的模型:
- 让业务人员能看得懂整个流程
- 让开发能快速定位问题与扩展节点
- 让运维可以通过配置而不是代码来调整规则
当你面对的是 固定的状态演进,选择状态机;
当你面对的是 复杂且动态的业务流程,选择工作流。
好的流程设计,不仅能减少错误,更能成为业务高效运转的一部分基础设施。
Author:
frank
License:
Copyright (c) 2019 CC-BY-NC-4.0 LICENSE