1. Flowable工作流引擎概述
Flowable是一个基于Java的轻量级业务流程管理(BPM)和工作流引擎,它实现了BPMN 2.0规范标准。作为一个开源项目,Flowable提供了完整的流程生命周期管理能力,从流程设计、部署到执行和监控,覆盖了企业级应用中的各种流程自动化需求。
在实际项目中,我们选择Flowable主要基于以下几个技术考量:
- 轻量级架构:核心引擎jar包仅约10MB,对系统资源占用小
- Spring深度集成:提供starter包实现开箱即用
- 高性能设计:采用异步事件机制,单节点可支持数千TPS
- 完善的API体系:覆盖流程全生命周期的操作接口
- 活跃的社区:持续更新维护,问题响应及时
与Activiti等同类产品相比,Flowable在Spring Boot支持、云原生适配和性能优化方面更具优势。特别是在微服务架构下,其模块化设计可以按需引入功能组件。
2. Spring Boot 3.x集成Flowable 7.x
2.1 环境准备与依赖配置
推荐使用以下技术栈组合:
- JDK 17/21(LTS版本)
- Spring Boot 3.1.0+
- Flowable 7.1.0+
Maven依赖配置示例:
xml复制<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>7.1.0</version>
</dependency>
2.2 数据库配置详解
Flowable需要独立的数据库存储流程定义和运行时数据。以MySQL为例的完整配置:
yaml复制spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/flowable_db?useSSL=false&characterEncoding=utf8
username: flowable
password: Flowable@123
type: com.zaxxer.hikari.HikariDataSource
hikari:
maximum-pool-size: 20
minimum-idle: 5
flowable:
database-schema-update: true
async-executor-activate: true
async-executor:
core-pool-size: 10
max-pool-size: 50
queue-capacity: 1000
关键参数说明:
database-schema-update: true表示自动创建/更新表结构async-executor-activate: 启用异步任务执行器- 建议使用HikariCP连接池,性能优于Druid
2.3 线程池优化配置
Flowable对线程池有特殊要求,必须提供名为applicationTaskExecutor的Bean:
java复制@Configuration
public class FlowableThreadConfig {
@Bean("applicationTaskExecutor")
public ThreadPoolTaskExecutor flowableExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int cores = Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(cores * 2);
executor.setMaxPoolSize(cores * 4);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("flowable-task-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
注意:线程池配置不当会导致流程实例卡死或性能下降。生产环境建议根据压测结果调整参数。
3. 流程设计与建模实践
3.1 使用官方设计器
推荐通过Docker快速启动设计器:
bash复制docker run -p 9090:8080 -d --name flowable-ui flowable/flowable-ui:6.8.0
访问http://localhost:9090/flowable-ui后,使用admin/test登录。
3.2 BPMN设计规范
设计业务流程时应遵循以下最佳实践:
- 明确开始/结束节点:每个流程必须有明确的起止点
- 合理使用网关:
- 排他网关(XOR)用于条件分支
- 并行网关(AND)用于同时执行多个任务
- 任务类型选择:
- 用户任务:需要人工审批的节点
- 服务任务:自动执行的业务逻辑
- 变量设计:
- 流程变量:整个流程生命周期有效
- 任务变量:仅当前任务有效
示例请假流程设计要点:
xml复制<bpmn2:process id="leave_approval" name="请假审批流程">
<bpmn2:startEvent id="startEvent"/>
<bpmn2:sequenceFlow sourceRef="startEvent" targetRef="applyTask"/>
<bpmn2:userTask id="applyTask" name="请假申请"
flowable:assignee="${applicant}">
<bpmn2:extensionElements>
<flowable:formProperty id="leaveType" name="请假类型" type="enum"/>
<flowable:formProperty id="days" name="请假天数" type="long"/>
</bpmn2:extensionElements>
</bpmn2:userTask>
<bpmn2:exclusiveGateway id="decisionGateway"/>
<bpmn2:sequenceFlow sourceRef="applyTask" targetRef="decisionGateway"/>
<bpmn2:sequenceFlow sourceRef="decisionGateway" targetRef="managerTask">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">
${days > 3}
</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:userTask id="managerTask" name="经理审批"
flowable:candidateGroups="managers"/>
<bpmn2:endEvent id="endEvent"/>
</bpmn2:process>
3.3 流程部署方案
推荐两种部署方式:
方案一:静态资源部署
将BPMN文件放在resources/bpmn目录下,启动时自动部署:
java复制@Component
public class ProcessDeployer implements CommandLineRunner {
@Autowired
private RepositoryService repositoryService;
@Override
public void run(String... args) throws Exception {
Resource[] resources = new PathMatchingResourcePatternResolver()
.getResources("classpath*:/bpmn/*.bpmn20.xml");
DeploymentBuilder deployment = repositoryService.createDeployment();
for (Resource r : resources) {
deployment.addInputStream(r.getFilename(), r.getInputStream());
}
deployment.deploy();
}
}
方案二:动态API部署
通过接口上传BPMN文件:
java复制@PostMapping("/deploy")
public String deployProcess(@RequestParam("file") MultipartFile file) {
Deployment deployment = repositoryService.createDeployment()
.addBytes(file.getOriginalFilename(), file.getBytes())
.deploy();
return deployment.getId();
}
4. 流程运行时管理
4.1 流程实例启动
标准启动方式需要设置业务键和流程变量:
java复制public String startProcess(String processKey, String businessKey) {
// 设置流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("applicant", getCurrentUserId());
variables.put("startTime", LocalDateTime.now());
// 设置认证信息
identityService.setAuthenticatedUserId(getCurrentUserId());
// 启动实例
ProcessInstance instance = runtimeService.startProcessInstanceByKey(
processKey,
businessKey,
variables);
// 清除认证
identityService.setAuthenticatedUserId(null);
return instance.getId();
}
业务键设计建议:使用"业务类型+ID"格式,如"LEAVE-20230001"
4.2 任务查询与处理
待办任务查询:
java复制public List<TaskInfo> getTodoTasks(String userId) {
return taskService.createTaskQuery()
.taskAssignee(userId)
.orderByTaskCreateTime().desc()
.list()
.stream()
.map(t -> new TaskInfo(
t.getId(),
t.getName(),
t.getProcessInstanceId(),
runtimeService.getVariable(t.getProcessInstanceId(), "businessKey")))
.collect(Collectors.toList());
}
任务审批处理:
java复制@Transactional
public void completeTask(String taskId, boolean approved, String comment) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
throw new RuntimeException("任务不存在");
}
// 添加审批意见
taskService.addComment(taskId, task.getProcessInstanceId(), comment);
// 设置审批结果变量
Map<String, Object> vars = new HashMap<>();
vars.put("approved", approved);
// 完成任务
taskService.complete(taskId, vars);
}
4.3 流程历史查询
获取流程审批历史记录:
java复制public List<HistoricActivity> getProcessHistory(String processInstanceId) {
return historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc()
.list()
.stream()
.map(a -> new HistoricActivity(
a.getActivityName(),
a.getAssignee(),
a.getStartTime(),
a.getEndTime(),
a.getDurationInMillis()))
.collect(Collectors.toList());
}
5. 高级特性与最佳实践
5.1 动态任务分配
实现灵活的审批人配置:
java复制// 在流程启动前设置候选人
runtimeService.addUserIdentityLink(
processInstanceId,
"manager1",
IdentityLinkType.CANDIDATE);
// 或者使用任务监听器动态分配
public class DynamicAssigneeListener implements TaskListener {
@Override
public void notify(DelegateTask task) {
String dept = (String) task.getVariable("department");
String assignee = findDepartmentManager(dept);
task.setAssignee(assignee);
}
}
5.2 多实例会签
配置会签任务(多人审批):
xml复制<userTask id="multiReview" name="多部门会签">
<multiInstanceLoopCharacteristics
isSequential="false"
flowable:collection="${reviewers}"
flowable:elementVariable="reviewer">
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
5.3 流程版本管理
处理流程定义更新:
java复制public void updateProcessDefinition(String processKey) {
// 1. 挂起旧版本的所有实例
List<ProcessDefinition> oldDefinitions = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey(processKey)
.list();
for (ProcessDefinition pd : oldDefinitions) {
repositoryService.suspendProcessDefinitionById(pd.getId());
}
// 2. 部署新版本
deployProcess(processKey);
// 3. 可选择迁移运行中的实例
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(processInstanceId)
.moveActivityIdTo("oldTask", "newTask")
.changeState();
}
6. 性能优化建议
-
数据库优化:
- 为ACT_RU_*表添加合适索引
- 定期归档历史数据到ACT_HI_*表
- 配置连接池监控
-
异步执行配置:
yaml复制flowable:
async-executor:
activate: true
core-pool-size: 10
max-pool-size: 50
queue-capacity: 1000
seconds-to-wait-on-shutdown: 60
- 缓存策略:
- 启用流程定义缓存
- 配置二级缓存
java复制@Configuration
public class FlowableCacheConfig {
@Bean
public FlowableCachingConfigurer flowableCaching() {
return new FlowableCachingConfigurer() {
@Override
public void configure(FlowableCacheConfigurer configurer) {
configurer
.enableProcessDefinitionCache()
.enableProcessModelCache()
.setProcessDefinitionCacheSize(1000);
}
};
}
}
- 监控指标:
java复制@RestController
@RequestMapping("/metrics")
public class FlowableMetricsController {
@Autowired
private ProcessEngine processEngine;
@GetMapping("/stats")
public Map<String, Object> getEngineStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeProcessInstances",
runtimeService.createProcessInstanceQuery().count());
stats.put("jobsWaiting",
managementService.createJobQuery().count());
stats.put("completedToday",
historyService.createHistoricProcessInstanceQuery()
.finishedAfter(DateUtil.getStartOfDay())
.count());
return stats;
}
}
7. 常见问题排查
7.1 流程实例卡住
现象:流程实例长时间停留在某个节点
排查步骤:
- 检查ACT_RU_TASK表确认当前任务
- 查询ACT_RU_JOB表查看异步作业
- 检查ACT_RU_EVENT_SUBSCR表的事件订阅
- 查看日志中是否有异常堆栈
解决方案:
java复制// 1. 手动触发作业
managementService.executeJob(jobId);
// 2. 重置流程变量
runtimeService.setVariable(instanceId, "retryCount", 0);
// 3. 跳过当前节点
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(instanceId)
.moveActivityIdTo(currentTaskId, nextTaskId)
.changeState();
7.2 任务分配异常
现象:任务未正确分配给目标用户
检查清单:
- 确认ACT_RU_IDENTITYLINK表的关联关系
- 检查任务监听器是否正常执行
- 验证候选人查询逻辑
- 检查用户组配置
7.3 性能瓶颈
优化方向:
- 分析慢SQL并优化
- 增加异步处理比例
- 调整事务隔离级别
- 优化流程设计(减少并行网关)
8. 生产环境建议
-
高可用架构:
- 部署多个引擎实例
- 使用共享数据库
- 配置负载均衡
-
灾备方案:
- 定期备份流程定义
- 实现实例恢复接口
- 建立监控告警机制
-
安全控制:
- 限制管理API访问
- 加密敏感流程变量
- 实现审计日志
-
扩展开发:
- 自定义表单引擎
- 开发流程设计器插件
- 集成消息通知系统
通过以上完整的实施方案,企业可以构建稳定高效的工作流系统。在实际项目中,建议先从简单流程开始验证,再逐步扩展复杂场景。Flowable的灵活性和扩展性能够满足大多数企业的流程自动化需求。