1. 工作流引擎的技术选型思考
第一次接触Activiti是在2015年一个OA系统项目中,当时团队在JBPM和Activiti之间犹豫不决。最终选择Activiti 5.x版本的原因很简单——它轻量级的架构和清晰的API设计特别适合Java技术栈。如今Activiti已经发展到7.x版本,与SpringBoot的集成变得更加优雅。
工作流引擎本质上是一种状态机,用来管理业务流程的生命周期。在审批流、订单处理、工单系统等场景中,它能将复杂的业务逻辑可视化,并通过引擎驱动流程流转。相比硬编码实现状态跳转,工作流引擎提供了以下不可替代的价值:
- 流程可视化:通过BPMN 2.0标准流程图直观展示业务流程
- 灵活调整:修改流程定义无需重新部署代码
- 历史追溯:完整记录流程实例的每个环节
- 权限控制:精细化的任务分配和办理机制
2. 环境搭建与基础配置
2.1 依赖引入的正确姿势
在SpringBoot 2.7.x项目中,引入Activiti 7的起步依赖需要注意版本兼容性。以下是经过生产验证的依赖配置:
xml复制<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
关键提示:Activiti 7.x默认使用Spring Security进行权限控制,如果项目中没有安全框架需求,需要显式排除:
xml复制<exclusions> <exclusion> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </exclusion> </exclusions>
2.2 数据库配置的坑与解决方案
Activiti默认会在启动时自动创建28张表,这些表分为5大类:
- ACT_RE_*:流程定义和静态资源存储
- ACT_RU_*:运行时流程实例数据
- ACT_HI_*:历史流程数据
- ACT_GE_*:通用数据(如二进制资源)
- ACT_ID_*:身份认证相关
生产环境建议关闭自动建表功能,改为使用Flyway等工具管理:
yaml复制spring:
activiti:
database-schema-update: false
db-history-used: true
3. 流程建模实战
3.1 BPMN设计器选型
推荐使用Eclipse的Activiti插件或在线工具bpmn.io。对于团队协作,Camunda Modeler是更好的选择,它支持:
- 拖拽式流程设计
- 属性面板配置
- 表单字段绑定
- 多泳道任务分配
3.2 典型审批流实现
以请假流程为例,完整BPMN应包含:
- 开始事件(Start Event)
- 用户任务(提交申请)
- 排他网关(判断请假天数)
- 并行网关(多级审批场景)
- 服务任务(调用业务系统)
- 结束事件(End Event)
java复制@GetMapping("/deploy")
public String deploy() {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("processes/leave.bpmn20.xml")
.name("请假流程")
.deploy();
return "部署成功,ID:" + deployment.getId();
}
4. 运行时控制与API详解
4.1 流程实例管理
启动流程实例时需要注意业务键(businessKey)的使用:
java复制ProcessInstance instance = runtimeService.startProcessInstanceByKey(
"leaveProcess",
"LEAVE_202306001",
variables);
经验之谈:businessKey应该使用有业务意义的标识(如订单号),而不是简单的UUID,这对后续查询和关联非常重要。
4.2 任务查询与办理
任务分配有三种模式:
- 固定分配(assignee)
- 候选人(candidateUser/candidateGroup)
- 动态分配(通过监听器实现)
java复制// 查询待办任务
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateOrAssigned(userId)
.processDefinitionKey("leaveProcess")
.list();
// 办理任务
taskService.complete(taskId, variables);
5. 高级特性与性能优化
5.1 异步执行器调优
Activiti使用异步执行器处理耗时操作,默认配置可能不满足生产需求:
yaml复制spring:
activiti:
async-executor-activate: true
async-executor-thread-pool-size: 10
async-executor-queue-size: 100
5.2 历史数据归档策略
对于高频业务,历史表会快速膨胀。建议配置:
java复制managementService.executeCommand(new CustomSqlExecution(
HistoryTableManager.class,
manager -> {
manager.bulkDeleteHistoricProcessInstances(ids);
return null;
}
));
6. 常见问题排查指南
6.1 事务不生效问题
现象:流程状态更新了,但业务数据没保存
解决方案:
- 检查是否在同一个@Transactional中
- 确认没有在监听器中抛出RuntimeException
6.2 流程图乱码问题
在application.yml中添加:
yaml复制spring:
activiti:
activity-font-name: 宋体
label-font-name: 宋体
7. 生产环境最佳实践
- 流程定义版本管理:每次修改都创建新版本,不要直接更新
- 变量使用规范:避免存储大对象,优先用引用ID
- 监控指标采集:跟踪以下关键指标
- 流程平均耗时
- 任务积压数
- 节点停留时间
java复制// 获取流程定义图(高亮当前节点)
ProcessDiagramGenerator diagramGenerator = processEngineConfiguration
.getProcessDiagramGenerator();
InputStream is = diagramGenerator.generateDiagram(
bpmnModel,
"png",
highLightedActivities,
Collections.emptyList());
经过多个项目的实践验证,这套技术方案能够支撑日均10万+流程实例的运行。对于更复杂的场景,可以考虑结合规则引擎(Drools)实现动态路由决策。