ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring Boot集成Flowable:3个注解快速构建审批流

Spring Boot集成Flowable:3个注解快速构建审批流 1. 项目概述当Spring Boot遇上Flowable在后台管理系统的开发里审批流是个绕不开的坎。无论是请假、报销还是工单流转背后都是一套逻辑严谨的流程控制。传统做法是硬编码状态机if-else满天飞流程一改就得伤筋动骨。后来我们引入了工作流引擎把流程逻辑从业务代码里抽离出来用可视化的方式定义用引擎来驱动这才算走上了正道。Flowable作为Activiti的一个分支是目前Java生态里非常活跃的一款轻量级工作流引擎。它原生支持BPMN 2.0标准与Spring Boot的集成堪称无缝。但很多朋友初上手时面对Flowable那一套API和一堆数据库表还是会觉得有点“重”心想我就想快速搭个请假审批有必要搞这么复杂吗答案是用对方法一点都不复杂。今天要聊的就是如何用Spring Boot接上Flowable并且只靠3个核心注解就能快速搭建并运行一个完整的请假审批流程。这3个注解就像是三个“开关”能帮你把Flowable引擎的能力以最Spring Boot的方式注入到你的业务服务里让流程的启动、任务处理和监听变得异常简单。我们不止讲怎么做更会拆解为什么这么做以及在实际操作中我踩过哪些坑、总结出哪些技巧。2. 核心思路注解驱动与职责分离在深入代码之前我们先理清整个方案的设计思路。核心目标是用最少的代码、最Spring Boot的方式让工作流跑起来。这里的“少”不是功能阉割而是通过合理的抽象和框架集成把繁琐的引擎API调用隐藏起来。2.1 为什么是这三个注解我们选定的三个注解是ProcessRuntime、TaskRuntime和EventListener。它们分别对应了Flowable与Spring集成中的三个关键角色。ProcessRuntime这是流程实例的“发动机”。它的职责是启动流程、查询流程实例、挂起或激活流程。在请假场景里“提交请假申请”这个动作本质上就是使用ProcessRuntime启动一个定义好的“请假流程”。TaskRuntime这是用户任务的“操作台”。流程流转到某个用户任务比如“经理审批”时具体的审批人就需要通过TaskRuntime来查询待办任务、签收任务、完成任务同意或驳回以及查询任务相关的变量和附件。EventListener这是流程的“耳朵”和“哨兵”。工作流引擎在运行过程中会抛出各种事件比如任务创建了、任务完成了、流程结束了。通过EventListener注解我们可以让Spring Bean中的方法监听这些特定事件从而在关键时刻执行业务逻辑例如发送通知、更新业务状态、记录日志等。这个组合实现了完美的职责分离。业务服务如LeaveService只关心启动流程和传递业务参数任务处理如TaskService只关心如何操作具体的任务项而事件监听器如LeaveProcessEventListener则负责处理流程推进过程中的副作用。三者通过Flowable引擎内部的事件机制松散耦合任何一方的修改都不会直接影响其他方。2.2 流程定义与业务数据的绑定策略另一个关键思路是如何将Flowable流程实例与你的业务数据比如一张t_leave请假单表关联起来。硬编码在流程变量里那会让流程变量变得臃肿且难以维护。我们的策略是使用业务主键Business Key进行松耦合关联。在启动流程实例时将业务实体的ID如leaveId作为businessKey传入。此后在任何需要获取业务数据的场景如任务办理、事件监听都可以通过runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(leaveId)来反向找到流程实例进而再通过leaveId去查询业务数据库。这样做的好处是流程引擎表只存储流程运行状态和必要的控制变量完整的业务数据仍留在业务库中两者通过一个简单的字符串键关联清晰且易于扩展。3. 环境准备与基础配置理论清晰了我们开始动手。首先需要一个干净的Spring Boot工程。3.1 依赖引入与版本选择在pom.xml中关键依赖是flowable-spring-boot-starter。版本选择需要谨慎需确保与你的Spring Boot版本兼容。以当前主流版本为例properties java.version17/java.version spring-boot.version3.1.5/spring-boot.version flowable.version7.0.0/flowable.version /properties dependencies !-- Spring Boot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Flowable 核心启动器 -- dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version${flowable.version}/version /dependency !-- 数据库这里用H2内存数据库方便演示 -- dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency !-- Lombok 简化代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies注意Flowable 7.x 与 Spring Boot 3.x 兼容性较好。如果你使用的是Spring Boot 2.x可能需要对应选择Flowable 6.x版本。引入starter后Flowable会自动配置数据源、事务管理器以及引擎本身并默认创建所需的数十张表。3.2 应用配置与表结构初始化在application.yml中我们需要进行一些基本配置spring: datasource: url: jdbc:h2:mem:flowable-db;DB_CLOSE_DELAY-1;DB_CLOSE_ON_EXITFALSE driver-class-name: org.h2.Driver username: sa password: h2: console: enabled: true # 开启H2控制台方便查看流程数据表 path: /h2-console # Flowable 配置 flowable: async-executor-activate: false # 开发环境可关闭异步执行器简化调试 database-schema-update: true # 自动创建/更新表结构生产环境建议设为false并通过脚本管理 history-level: audit # 历史级别audit会保存流程实例、任务、变量等核心历史数据启动应用你会发现控制台打印了大量Creating表结构的SQL日志。此时访问http://localhost:8080/h2-console连接上H2数据库就能看到ACT_RE_*存储流程定义、ACT_RU_*存储运行时数据、ACT_HI_*存储历史数据和ACT_ID_*存储身份数据四大类表。这说明Flowable引擎已经就绪。3.3 绘制并部署BPMN流程图工作流的核心是流程定义。我们需要一个BPMN 2.0的XML文件来描述请假流程。你可以使用Flowable提供的在线设计器通常集成在其UI应用中或者使用Eclipse的BPMN 2.0插件、IntelliJ IDEA的Flowable插件来绘制。这里给出一个最简化的“员工请假-经理审批”流程的XML定义 (leave-process.bpmn20.xml)应放在src/main/resources/processes/目录下?xml version1.0 encodingUTF-8? definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:flowablehttp://flowable.org/bpmn targetNamespacehttp://www.flowable.org/processdef process idleaveApproval name员工请假审批流程 isExecutabletrue !-- 开始事件 -- startEvent idstartEvent name提交申请/ !-- 员工提交请假申请任务 -- userTask idsubmitLeave name提交请假单 flowable:assignee${applicantId} extensionElements flowable:formProperty idleaveType name请假类型 typestring requiredtrue/ flowable:formProperty idduration name请假时长(天) typedouble requiredtrue/ flowable:formProperty idreason name事由 typestring/ /extensionElements /userTask !-- 经理审批任务 -- userTask idmanagerApprove name经理审批 flowable:candidateUsers${managerId} extensionElements flowable:formProperty idapprovalResult name审批结果 typeenum flowable:value idagree name同意/ flowable:value idreject name驳回/ /flowable:formProperty flowable:formProperty idcomment name审批意见 typestring/ /extensionElements /userTask !-- 排他网关根据审批结果决定流向 -- exclusiveGateway iddecisionGateway name审批决策/ !-- 审批通过流程结束 -- endEvent idendEventApproved name审批通过结束/ !-- 审批驳回流程结束 -- endEvent idendEventRejected name审批驳回结束/ !-- 顺序流连接 -- sequenceFlow idflow1 sourceRefstartEvent targetRefsubmitLeave/ sequenceFlow idflow2 sourceRefsubmitLeave targetRefmanagerApprove/ sequenceFlow idflow3 sourceRefmanagerApprove targetRefdecisionGateway/ sequenceFlow idflow4 sourceRefdecisionGateway targetRefendEventApproved conditionExpression xsi:typetFormalExpression ![CDATA[${approvalResult agree}]] /conditionExpression /sequenceFlow sequenceFlow idflow5 sourceRefdecisionGateway targetRefendEventRejected conditionExpression xsi:typetFormalExpression ![CDATA[${approvalResult reject}]] /conditionExpression /sequenceFlow /process /definitions这个流程很简单开始 → 员工提交任务 → 经理审批任务 → 根据审批结果同意/驳回网关决策 → 结束。注意flowable:assignee和flowable:candidateUsers它们用于指定任务的办理人或候选人。这里使用了表达式${applicantId}和${managerId}意味着这些值将在流程运行时动态传入。将BPMN文件放在resources/processes/目录后Flowable Spring Boot Starter会在应用启动时自动扫描并部署它。你可以在启动日志中看到类似Deployed processes: [leaveApproval (v1)]的信息。4. 核心注解驱动开发实战环境与流程定义都已就绪现在进入核心环节如何使用三个注解来驱动整个流程。4.1 使用 ProcessRuntime 启动流程首先我们创建一个请假服务LeaveService并注入ProcessRuntime。import org.flowable.engine.RuntimeService; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; Service Slf4j RequiredArgsConstructor public class LeaveService { // 关键注解注入流程运行时服务 private final RuntimeService runtimeService; /** * 提交请假申请启动流程 * param applicantId 申请人ID * param managerId 审批经理ID * param leaveRequest 请假请求数据 * return 启动的流程实例ID */ Transactional public String submitLeaveRequest(String applicantId, String managerId, LeaveRequest leaveRequest) { // 1. 持久化业务数据这里简化直接使用DTO // 实际项目中应先保存 leaveRequest 到业务表并获取生成的 leaveId String businessKey LEAVE_ System.currentTimeMillis(); // 模拟业务主键 // 2. 设置流程变量 MapString, Object variables new HashMap(); variables.put(applicantId, applicantId); variables.put(managerId, managerId); variables.put(leaveType, leaveRequest.getLeaveType()); variables.put(duration, leaveRequest.getDuration()); variables.put(reason, leaveRequest.getReason()); // 将业务主键也存入变量方便后续查询 variables.put(businessKey, businessKey); // 3. 使用 ProcessRuntime 启动流程实例 // 参数流程定义Key, 业务主键, 流程变量 ProcessInstance processInstance runtimeService.startProcessInstanceByKey( leaveApproval, // 对应BPMN文件中的 process id businessKey, variables ); String processInstanceId processInstance.getId(); log.info(请假流程启动成功。流程实例ID: {}, 业务主键: {}, processInstanceId, businessKey); return processInstanceId; } } // 简单的请假请求DTO Data class LeaveRequest { private String leaveType; // 年假、病假等 private Double duration; private String reason; }关键点解析RuntimeService是由Flowable自动配置的BeanAutowired或构造器注入即可。startProcessInstanceByKey是最常用的启动方式使用流程定义的id即BPMN中的process id。businessKey是关联业务数据的生命线务必使用有业务意义的唯一标识。启动流程是一个事务性操作建议在Service方法上添加Transactional注解确保业务数据与流程实例创建的原子性。4.2 使用 TaskRuntime 处理审批任务流程启动后会自动流转到“提交请假单”任务并因为assignee是申请人自己所以该任务会自动完成如果配置了flowable:skipExpression可能不会自动创建这里我们假设需要手动完成。接着会到达“经理审批”任务。现在我们需要为经理提供一个查询待办和审批的接口。创建TaskService注入TaskService(注意是Flowable的不是Spring的)。import org.flowable.engine.TaskService; import org.flowable.task.api.Task; import org.flowable.task.api.TaskQuery; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.List; import java.util.Map; Service Slf4j RequiredArgsConstructor public class TaskService { // 关键注解注入任务服务 private final TaskService taskService; /** * 查询用户的待办任务 * param userId 用户ID * return 待办任务列表 */ public ListTask getTodoTasks(String userId) { // 创建任务查询 TaskQuery taskQuery taskService.createTaskQuery(); // 设置查询条件候选人包含该用户 或 办理人是该用户 // 对于 candidateUsers 方式分配的任务用户需要先“签收”才能成为办理人 ListTask tasks taskQuery .taskCandidateOrAssigned(userId) // 查询作为候选人或已被指派的任务 .orderByTaskCreateTime().desc() // 按创建时间倒序 .list(); // 可以进一步封装将Task对象转换为前端需要的VO return tasks; } /** * 签收任务将候选任务变为个人任务 * param taskId 任务ID * param userId 用户ID */ Transactional public void claimTask(String taskId, String userId) { taskService.claim(taskId, userId); log.info(用户 {} 签收了任务 {}, userId, taskId); } /** * 完成任务例如经理审批 * param taskId 任务ID * param approvalResult 审批结果和意见 */ Transactional public void completeTask(String taskId, MapString, Object approvalResult) { // 完成任务并设置流程变量 // 这里传入的 approvalResult Map 应包含流程中需要的变量如 approvalResult, comment taskService.complete(taskId, approvalResult); log.info(任务 {} 已完成审批结果: {}, taskId, approvalResult); } /** * 获取任务关联的流程变量用于渲染表单或展示详情 * param taskId 任务ID * return 流程变量Map */ public MapString, Object getTaskVariables(String taskId) { return taskService.getVariables(taskId); } }实操心得taskCandidateOrAssigned(userId)这个查询条件非常实用它同时覆盖了“我是候选人”和“我已签收”两种状态的任务避免了前端需要区分查询的麻烦。taskService.complete(taskId, variables)方法中的variables参数至关重要。它会在完成任务的同时将这些变量设置到流程实例的上下文中。在我们的流程里网关决策依赖的approvalResult变量就是通过这里传入的。任务操作claim,complete通常也建议放在事务中特别是当完成任务后需要同步更新业务状态时虽然这个更新更推荐在监听器中做。4.3 使用 EventListener 监听流程事件流程在运行但我们还需要知道它什么时候到了关键节点以便执行一些“副作用”逻辑比如发送通知、更新业务状态。这时就需要事件监听器。创建一个事件监听器类使用Spring的EventListener注解来监听Flowable的事件。import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; import org.flowable.engine.delegate.event.FlowableEngineEntityEvent; import org.flowable.engine.delegate.event.FlowableEvent; import org.flowable.task.api.Task; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import lombok.extern.slf4j.Slf4j; Component Slf4j public class LeaveProcessEventListener { /** * 监听任务创建事件 * 当一个新的用户任务被创建时触发可用于发送待办通知。 */ EventListener(condition #event.type TASK_CREATED) public void onTaskCreated(FlowableEngineEntityEvent event) { Task task (Task) event.getEntity(); String taskName task.getName(); String processInstanceId task.getProcessInstanceId(); log.info([事件监听] 任务创建任务名称{}, 流程实例ID{}, taskName, processInstanceId); // 这里可以添加业务逻辑例如 // 1. 查询任务候选人/办理人 // 2. 调用消息服务发送邮件、钉钉、微信通知 // 3. 记录任务创建日志到业务库 if (经理审批.equals(taskName)) { String assignee task.getAssignee(); // 如果是候选人方式assignee可能为null需要通过taskService.getIdentityLinksForTask获取候选人 log.info(-- 需要发送审批通知给用户: {}, assignee); // notificationService.sendToUser(assignee, 您有一个待审批的请假单); } } /** * 监听任务完成事件 * 当一个用户任务被完成时触发可用于更新业务状态。 */ EventListener(condition #event.type TASK_COMPLETED) public void onTaskCompleted(FlowableEngineEntityEvent event) { Task task (Task) event.getEntity(); String taskDefinitionKey task.getTaskDefinitionKey(); // 对应BPMN中的任务ID如 managerApprove String processInstanceId task.getProcessInstanceId(); log.info([事件监听] 任务完成任务定义Key{}, 流程实例ID{}, taskDefinitionKey, processInstanceId); // 关键业务逻辑根据完成的任务节点更新对应的业务数据状态 if (managerApprove.equals(taskDefinitionKey)) { // 1. 获取流程变量中的审批结果和业务主键 // 注意事件监听器中无法直接获取TaskService需要通过RuntimeService获取变量 // 通常需要在事件触发时将关键业务变量如businessKey也放入引擎的变量中 // 2. 根据businessKey找到业务实体更新其状态为“已审批”或“已驳回” // 3. 记录审批日志 // businessService.updateStatus(businessKey, newStatus); } } /** * 监听流程实例结束事件 * 当整个流程实例结束时触发可用于进行最终的资源清理或状态归档。 */ EventListener(condition #event.type PROCESS_COMPLETED) public void onProcessCompleted(FlowableEngineEntityEvent event) { String processInstanceId event.getProcessInstanceId(); log.info([事件监听] 流程实例结束ID{}, processInstanceId); // 例如将业务单据状态标记为“流程已结束”或触发后续的归档操作 } }深度解析与避坑指南事件类型Flowable有丰富的事件类型TASK_CREATED,TASK_COMPLETED,PROCESS_STARTED,PROCESS_COMPLETED,ACTIVITY_COMPLETED等。EventListener的condition属性使用SpEL表达式来过滤特定事件非常灵活。变量获取时机这是最容易出错的地方。在TASK_COMPLETED事件中任务实体task已经完成通过taskService.getVariables(taskId)可能无法获取到任务完成时新设置的变量如approvalResult。更可靠的做法是方案A在完成任务taskService.complete后立即在业务代码里更新状态而不是依赖事件监听器。这更直接事务也更容易控制。方案B如果坚持在监听器中处理可以通过RuntimeService获取流程实例级别的变量因为任务完成时设置的变量会提升为流程变量。使用runtimeService.getVariables(processInstanceId)。事务边界事件监听器默认在发布事件的同一事务中执行。这意味着如果监听器里抛异常会导致触发该事件的操作如完成任务也回滚。务必确保监听器逻辑的健壮性或者使用Async和Transactional(propagation Propagation.REQUIRES_NEW)将其放入独立事务中避免影响主流程。性能考量高频事件如ACTIVITY_STARTED的监听器逻辑要尽可能轻量避免阻塞主线程或拖慢流程引擎。5. 构建REST API与前端交互服务层准备好了我们需要通过Controller暴露API给前端调用。这里构建一组最简化的RESTful接口。import org.springframework.web.bind.annotation.*; import lombok.RequiredArgsConstructor; import java.util.List; import java.util.Map; RestController RequestMapping(/api/leave) RequiredArgsConstructor public class LeaveController { private final LeaveService leaveService; private final TaskService taskService; // 注意这是我们自己写的TaskService PostMapping(/submit) public ApiResponseString submit(RequestBody LeaveSubmitRequest request) { // request 应包含 applicantId, managerId, leaveRequest String processInstanceId leaveService.submitLeaveRequest( request.getApplicantId(), request.getManagerId(), request.getLeaveRequest() ); return ApiResponse.success(流程启动成功, processInstanceId); } GetMapping(/tasks) public ApiResponseListTask getTasks(RequestParam String userId) { ListTask tasks taskService.getTodoTasks(userId); return ApiResponse.success(tasks); } PostMapping(/task/{taskId}/claim) public ApiResponseVoid claimTask(PathVariable String taskId, RequestParam String userId) { taskService.claimTask(taskId, userId); return ApiResponse.success(签收成功); } PostMapping(/task/{taskId}/complete) public ApiResponseVoid completeTask(PathVariable String taskId, RequestBody MapString, Object variables) { // variables 例如: {approvalResult: agree, comment: 情况属实同意} taskService.completeTask(taskId, variables); return ApiResponse.success(任务完成); } } // 简单的请求响应封装 Data class ApiResponseT { private int code; private String msg; private T data; // 省略静态工厂方法 } Data class LeaveSubmitRequest { private String applicantId; private String managerId; private LeaveRequest leaveRequest; }前端应用如Vue、React就可以通过这些接口来提交请假单启动流程。用户登录后查询自己的待办任务列表。点击“办理”签收任务。在审批页面看到从getTaskVariables获取的请假详情并填写审批意见点击“同意”或“驳回”来完成任务。6. 流程监控、调试与进阶优化一个可运行的基础流程搭建完毕了但在实际开发中我们还需要“看见”流程是如何运行的以及处理一些更复杂的情况。6.1 利用Flowable REST API与UI应用Flowable Starter默认提供了一套REST API/flowable-rest/service/和一个管理UI需要额外引入flowable-ui依赖。对于开发调试而言管理UI非常直观。你可以看到已部署的流程定义、正在运行的流程实例、各个节点的状态、流程变量等。虽然生产环境可能不会直接使用这个UI但在开发阶段它是排查流程流转问题不可或缺的工具。6.2 流程变量管理策略流程变量是连接流程引擎与业务数据的桥梁。管理不善会变成一团乱麻。精简原则只把流程流转必需的数据作为流程变量如applicantId,managerId,approvalResult。完整的业务对象如LeaveRequest应以businessKey为索引从业务库查询。序列化注意如果变量值是复杂对象Flowable会将其序列化后存入ACT_GE_BYTEARRAY表。确保该对象实现了Serializable接口并考虑序列化兼容性问题。更推荐的做法是存ID或JSON字符串。作用域变量有任务作用域和流程实例作用域。taskService.setVariableLocal设置的任务变量只在当前任务有效。通常审批意见comment适合作为任务变量而审批结果approvalResult这种影响网关决策的必须在完成任务时通过taskService.complete(taskId, variables)设置为流程变量。6.3 处理会签、或签等高级任务实际审批中经理审批可能不是一个人而是需要多个部门负责人会签或者其中任意一人同意即可或签。这在BPMN中可以通过“多实例活动”来实现。修改managerApprove用户任务为其添加多实例配置userTask idmanagerApprove name经理会签 flowable:candidateUsers${managerIds} extensionElements !-- ... 表单属性同上 ... -- /extensionElements !-- 多实例配置 -- multiInstanceLoopCharacteristics isSequentialfalse flowable:collectionmanagerIds flowable:elementVariablesingleManager completionCondition${nrOfCompletedInstances / nrOfInstances 0.5}/completionCondition /multiInstanceLoopCharacteristics /userTaskisSequentialfalse表示并行会签。flowable:collection指定一个存储了候选人ID列表的流程变量如managerIds它是一个List。flowable:elementVariable指定在每次循环中当前候选人的ID被赋值给哪个变量singleManager。completionCondition是完成条件。这里示例是完成人数超过一半50%即通过。你可以写更复杂的表达式如${nrOfCompletedInstances nrOfInstances}全部完成或基于聚合变量判断。在启动流程时你需要传入一个List类型的managerIds变量。引擎会自动为每个候选人创建独立的子任务。后端TaskService的查询和办理逻辑基本不变因为对于每个候选人来说他们看到的还是自己的那个子任务。6.4 集成业务表单与动态节点指派我们例子中使用了BPMN内嵌的extensionElements定义简单表单。但在实际复杂业务中表单通常由前端动态渲染表单结构存储在另一张表或JSON配置中。此时BPMN中只需定义任务节点表单的Key如formKey: leave_form可以作为任务的一个属性。任务办理时前端根据formKey去加载对应的表单配置。节点指派也一样assignee或candidateUsers可能不是写死的ID而是通过一个表达式调用Spring Bean的方法动态计算出来例如${ldapService.findDepartmentManager(applicantId)}。这需要在流程定义中配置flowable:delegateExpression或使用flowable:class指定一个实现了TaskAssignmentListener的Java类从而在运行时动态解析负责人。7. 常见问题排查与性能调优在实际部署和运行中你可能会遇到以下问题问题1启动流程后任务没有自动创建检查点首先确认流程是否成功部署查看启动日志。然后检查启动流程时传入的变量是否正确。特别是assignee或candidateUsers表达式所引用的变量如${applicantId}是否已正确设置并传入runtimeService.startProcessInstanceByKey的variables中。技巧开启Flowable的调试日志logging.level.org.flowableDEBUG可以非常详细地看到引擎每一步的执行逻辑和SQL是定位问题的利器。问题2查询待办任务速度慢原因ACT_RU_TASK表数据量过大且查询条件可能未走索引。优化历史数据归档定期将已结束的流程实例和历史任务从运行时表(ACT_RU_*)归档到历史表(ACT_HI_*)并清理运行时表。Flowable提供了HistoryService的相关API。索引优化确保ACT_RU_TASK表上的ASSIGNEE_,PROC_INST_ID_,CREATE_TIME_等字段有索引。Flowable自动创建的索引可能不全需要根据查询模式补充。分页查询在TaskQuery上务必使用.listPage(start, size)进行分页避免一次性拉取大量数据。问题3事件监听器导致事务回滚或性能瓶颈事务如前所述考虑将非核心的监听逻辑如发通知异步化Async并与主事务分离Transactional(propagation Propagation.REQUIRES_NEW)。性能对于像“发送短信”这种可能失败或耗时的操作不要放在同步监听器里。可以将其放入消息队列如RabbitMQ、Kafka由消费者异步处理。监听器只负责发消息。问题4流程定义变更后已运行的旧实例如何处理策略这是工作流管理的经典问题。Flowable支持流程定义的版本化。每次部署相同key的流程都会生成一个新版本。默认情况下新发起的流程实例会使用最新版本而已运行的旧实例会继续沿用启动时的版本。这保证了运行中流程的稳定性。迁移如果需要将旧实例迁移到新版本通常非常复杂需要手动编写迁移脚本调整运行时数据。因此在流程设计初期应尽量考虑周全上线后对流程定义的修改要谨慎非破坏性变更如修改表单字段名可以通过适配逻辑处理而结构性变更如增减节点最好通过新启一个流程定义Key来处理。通过以上七个部分的拆解我们从设计思路、环境搭建、注解核心使用、API构建、高级特性到问题排查完整地覆盖了用Spring Boot和Flowable搭建一个请假审批流程的全过程。这三个注解——ProcessRuntime、TaskRuntime、EventListener——就像三把钥匙帮你打开了Flowable集成Spring Boot的大门让工作流开发回归到熟悉的Spring编程模型中高效且清晰。
返回列表