1. 为什么需要工作流引擎
在传统企业级应用开发中,业务流程管理往往是最复杂的部分之一。以请假审批流程为例,需要处理:
- 员工提交申请
- 主管审批
- HR备案
- 系统同步考勤记录
- 结果通知申请人
如果采用硬编码方式实现,代码中会充满各种if-else分支,流程变更需要重新开发部署。而工作流引擎通过可视化流程设计+运行时引擎的方式,将业务流程从业务代码中解耦出来。
Activiti作为Apache旗下的开源工作流引擎,具有以下核心优势:
- 基于BPMN 2.0标准规范
- 轻量级设计,易于集成
- 丰富的Java API支持
- 活跃的社区生态
2. 环境准备与基础集成
2.1 依赖配置
在SpringBoot项目中引入Activiti 7的starter依赖:
<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter</artifactId> <version>7.1.0.M6</version> </dependency>关键依赖说明:
- activiti-spring-boot-starter:核心引擎
- mybatis-plus:Activiti 7默认使用MyBatis作为ORM框架
- h2:内存数据库(开发环境推荐)
注意:生产环境建议使用MySQL等正式数据库,需额外配置数据源
2.2 自动配置原理
SpringBoot启动时会自动:
- 创建28张工作流相关表(ACT_开头)
- 初始化ProcessEngine流程引擎实例
- 配置事务管理
- 暴露REST API端点(需手动开启)
可以通过application.yml调整配置:
activiti: database-schema-update: true # 自动更新数据库结构 async-executor-activate: true # 启用异步执行器 history-level: audit # 历史记录级别3. 流程设计与部署
3.1 BPMN 2.0设计规范
使用Eclipse插件或在线工具设计请假流程:
<bpmn2:process id="leaveProcess" name="请假流程"> <bpmn2:startEvent id="startEvent"/> <bpmn2:userTask id="leaderAudit" name="主管审批"/> <bpmn2:exclusiveGateway id="exclusiveGateway"/> <bpmn2:endEvent id="endEvent"/> <!-- 连线定义 --> </bpmn2:process>关键元素说明:
- UserTask:人工任务节点
- ServiceTask:自动服务节点
- ExclusiveGateway:排他网关(相当于if-else)
- ParallelGateway:并行网关(相当于and)
3.2 流程部署API
通过RepositoryService部署流程:
@Autowired private RepositoryService repositoryService; public void deployProcess() { Deployment deployment = repositoryService.createDeployment() .addClasspathResource("processes/leave.bpmn20.xml") .name("请假流程") .deploy(); log.info("部署ID: {}", deployment.getId()); }部署后可在ACT_RE_PROCDEF表查看流程定义。
4. 运行时流程控制
4.1 启动流程实例
@Autowired private RuntimeService runtimeService; public void startProcess(String businessKey) { Map<String, Object> variables = new HashMap<>(); variables.put("days", 3); // 流程变量 ProcessInstance instance = runtimeService.startProcessInstanceByKey( "leaveProcess", businessKey, variables ); }4.2 任务处理
查询待办任务:
@Autowired private TaskService taskService; public List<Task> getTasks(String assignee) { return taskService.createTaskQuery() .taskAssignee(assignee) .list(); }完成任务:
public void completeTask(String taskId) { Map<String, Object> variables = new HashMap<>(); variables.put("approved", true); taskService.complete(taskId, variables); }5. 高级特性实现
5.1 监听器配置
实现任务分配逻辑:
@Component public class LeaderTaskListener implements TaskListener { @Override public void notify(DelegateTask task) { String dept = (String) task.getVariable("dept"); String leader = userService.findDeptLeader(dept); task.setAssignee(leader); } }在BPMN中配置:
<bpmn2:userTask id="leaderAudit" activiti:assignee="${initiator}"> <bpmn2:extensionElements> <activiti:taskListener event="create" class="com.example.LeaderTaskListener"/> </bpmn2:extensionElements> </bpmn2:userTask>5.2 异步执行器
对于耗时操作(如调用外部API),应配置为异步:
<bpmn2:serviceTask id="syncAttendance" activiti:class="com.example.SyncAttendanceDelegate" activiti:async="true"/>需在application.yml中启用:
activiti: async-executor-activate: true async-executor-thread-pool-size: 106. 生产环境最佳实践
6.1 性能优化建议
数据库配置:
spring: datasource: hikari: maximum-pool-size: 20 connection-timeout: 30000历史数据归档:
historyService.createHistoricProcessInstanceQuery() .finished() .listPage(0, 100) .forEach(instance -> { historyService.deleteHistoricProcessInstance(instance.getId()); });
6.2 集群部署方案
- 共享数据库配置
- 启用分布式锁:
activiti: async-executor-lock-wait-time: 600000 - 建议使用Redis作为分布式锁存储
7. 常见问题排查
7.1 流程定义找不到
可能原因:
- 部署时XML文件路径错误
- 流程定义key不匹配
- 未正确配置资源目录
解决方案:
repositoryService.createProcessDefinitionQuery() .processDefinitionKey("leaveProcess") .list() // 验证流程定义是否存在7.2 事务回滚问题
典型场景:
- 业务流程异常时,需要回滚工作流状态
解决方案:
@Transactional public void approveLeave(Long leaveId) { leaveService.approve(leaveId); // 业务操作 taskService.complete(taskId); // 工作流操作 // 两者处于同一事务 }关键点:确保业务Service和TaskService在同一个@Transactional中
8. 监控与运维
8.1 监控指标暴露
通过SpringBoot Actuator暴露:
management: endpoints: web: exposure: include: activiti访问端点:
- /actuator/activiti:流程引擎状态
- /actuator/activiti/jobs:异步作业队列
8.2 日志配置建议
logging: level: org.activiti: DEBUG # 核心引擎日志 org.mybatis: WARN # 减少SQL日志建议结合ELK等日志系统实现:
- 流程执行轨迹追踪
- 异常任务告警
- 性能统计分析
9. 扩展开发建议
9.1 自定义表单开发
替代默认表单属性:
public class LeaveForm { @FormProperty(id = "reason", name = "请假原因") private String reason; @FormProperty(id = "days", name = "请假天数") private Integer days; }在流程变量中自动转换:
formService.saveFormData(taskId, form);9.2 REST API扩展
自定义Controller示例:
@RestController @RequestMapping("/api/workflow") public class WorkflowController { @PostMapping("/start") public Response startProcess(@RequestBody StartRequest request) { // 封装启动逻辑 } @GetMapping("/tasks") public List<TaskDTO> getTasks(@RequestParam String userId) { // 转换任务对象 } }建议实现:
- 分页查询
- 条件过滤
- DTO转换
10. 版本升级策略
从Activiti 5/6升级到7的注意事项:
数据库变更:
ALTER TABLE ACT_RU_TASK ADD COLUMN BUSINESS_KEY_ VARCHAR(255);API变化:
- 废弃IdentityService部分方法
- FormService接口调整
推荐步骤:
- 备份数据库
- 在新环境测试迁移
- 逐步替换旧服务
- 数据校验
实际项目中,我们通过灰度发布方式,用3周时间完成了核心流程引擎的升级,期间处理的主要兼容性问题包括历史任务查询API的变化和表单属性的存储格式调整。