Flowable工作流:从入门到实战

617 阅读4分钟

Flowable工作流:从入门到实战

一、什么是Flowable

Flowable是一个开源的轻量级业务流程引擎(BPMN 2.0),它起源于Activiti项目,是Activiti的继任者。Flowable提供了完整的工作流和业务流程管理(BPM)平台,支持流程定义、部署、执行、监控等全生命周期管理。

1.1 核心特性

  • BPMN 2.0标准支持:完全符合BPMN 2.0规范
  • 轻量级:可嵌入到任何Java应用中
  • 高性能:支持高并发场景
  • 灵活扩展:提供丰富的扩展点
  • 云原生:支持微服务架构

1.2 核心组件

Flowable主要由以下核心组件构成:

  • Flowable Engine:核心流程引擎
  • Flowable Modeler:流程建模工具
  • Flowable Task:任务管理应用
  • Flowable Admin:管理监控界面
  • Flowable REST:REST API接口

二、核心概念详解

2.1 BPMN 2.0基础

BPMN(Business Process Model and Notation)是业务流程建模与 notation 的标准。BPMN 2.0定义了一套标准的图形符号来表示业务流程。

基本元素
  • 事件(Event):流程中发生的事情,如开始事件、结束事件
  • 活动(Activity):流程中的工作单元,如用户任务、服务任务
  • 网关(Gateway):控制流程分支,如排他网关、并行网关
  • 连接线(Sequence Flow):连接各个元素

2.2 流程定义

流程定义是业务流程的静态描述,使用BPMN XML格式定义。一个典型的请假流程定义如下:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             targetNamespace="Examples">
    <process id="leaveRequest" name="请假流程" isExecutable="true">

        <!-- 开始事件 -->
        <startEvent id="startEvent" name="开始"/>

        <!-- 员工填写请假单 -->
        <userTask id="employeeTask" name="填写请假单"
                  flowable:assignee="${employee}"/>

        <!-- 部门经理审批 -->
        <userTask id="managerTask" name="经理审批"
                  flowable:candidateGroups="managers"/>

        <!-- 排他网关:根据天数决定是否需要HR审批 -->
        <exclusiveGateway id="gateway"/>

        <!-- HR审批(超过3天需要) -->
        <userTask id="hrTask" name="HR审批"
                  flowable:candidateGroups="hr"/>

        <!-- 结束事件 -->
        <endEvent id="endEvent" name="结束"/>

        <!-- 连接线 -->
        <sequenceFlow sourceRef="startEvent" targetRef="employeeTask"/>
        <sequenceFlow sourceRef="employeeTask" targetRef="managerTask"/>
        <sequenceFlow sourceRef="managerTask" targetRef="gateway"/>
        <sequenceFlow sourceRef="gateway" targetRef="hrTask">
            <conditionExpression>${days > 3}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow sourceRef="gateway" targetRef="endEvent">
            <conditionExpression>${days <= 3}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow sourceRef="hrTask" targetRef="endEvent"/>

    </process>
</definitions>

2.3 流程实例与执行

流程实例是流程定义的一次具体执行。一个流程定义可以创建多个流程实例,每个实例有独立的执行状态和变量。

三、快速入门

3.1 环境搭建

首先创建Maven项目,添加Flowable依赖:

<dependencies>
    <!-- Flowable核心引擎 -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-engine</artifactId>
        <version>7.0.0</version>
    </dependency>

    <!-- Flowable REST API -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-rest</artifactId>
        <version>7.0.0</version>
    </dependency>

    <!-- 数据库连接 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>2.2.224</version>
    </dependency>

    <!-- 日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.11</version>
    </dependency>
</dependencies>

3.2 初始化流程引擎

public class FlowableEngineConfig {

    private static ProcessEngine processEngine;

    public static ProcessEngine getProcessEngine() {
        if (processEngine == null) {
            synchronized (FlowableEngineConfig.class) {
                if (processEngine == null) {
                    // 配置流程引擎
                    ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                            .createStandaloneProcessEngineConfiguration();

                    // 配置数据库连接
                    configuration.setJdbcDriver("org.h2.Driver");
                    configuration.setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1");
                    configuration.setJdbcUsername("sa");
                    configuration.setJdbcPassword("");

                    // 自动创建/更新数据库表结构
                    configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

                    // 创建流程引擎
                    processEngine = configuration.buildProcessEngine();
                }
            }
        }
        return processEngine;
    }

    // 获取各个服务
    public static RepositoryService getRepositoryService() {
        return getProcessEngine().getRepositoryService();
    }

    public static RuntimeService getRuntimeService() {
        return getProcessEngine().getRuntimeService();
    }

    public static TaskService getTaskService() {
        return getProcessEngine().getTaskService();
    }

    public static HistoryService getHistoryService() {
        return getProcessEngine().getHistoryService();
    }

    public static ManagementService getManagementService() {
        return getProcessEngine().getManagementService();
    }
}

3.3 部署流程定义

public class ProcessDeploymentService {

    /**
     * 部署流程定义
     */
    public String deployProcess(String processName, String resourcePath) {
        Deployment deployment = FlowableEngineConfig.getRepositoryService()
                .createDeployment()
                .name(processName)
                .addClasspathResource(resourcePath)
                .deploy();

        System.out.println("流程部署成功,部署ID: " + deployment.getId());
        return deployment.getId();
    }

    /**
     * 查询已部署的流程列表
     */
    public List<ProcessDefinition> listProcesses() {
        return FlowableEngineConfig.getRepositoryService()
                .createProcessDefinitionQuery()
                .orderByProcessDefinitionName()
                .asc()
                .list();
    }
}

3.4 启动流程实例

public class ProcessInstanceService {

    /**
     * 启动流程实例
     */
    public ProcessInstance startProcess(String processDefinitionKey, Map<String, Object> variables) {
        ProcessInstance processInstance = FlowableEngineConfig.getRuntimeService()
                .startProcessInstanceByKey(processDefinitionKey, variables);

        System.out.println("流程实例启动成功,实例ID: " + processInstance.getId());
        System.out.println("业务Key: " + processInstance.getBusinessKey());

        return processInstance;
    }

    /**
     * 查询运行中的流程实例
     */
    public List<ProcessInstance> listRunningInstances() {
        return FlowableEngineConfig.getRuntimeService()
                .createProcessInstanceQuery()
                .orderByStartTime()
                .desc()
                .list();
    }
}

四、核心服务详解

Flowable通过服务层对外提供功能,主要包括以下服务:

4.1 RepositoryService(仓库服务)

管理流程定义和部署对象:

// 部署流程
Deployment deployment = repositoryService.createDeployment()
    .name("请假流程")
    .addClasspathResource("processes/leave-request.bpmn20.xml")
    .deploy();

// 查询流程定义
ProcessDefinition processDefinition = repositoryService
    .createProcessDefinitionQuery()
    .processDefinitionKey("leaveRequest")
    .singleResult();

// 挂起/激活流程定义
repositoryService.suspendProcessDefinitionById(processDefinitionId);
repositoryService.activateProcessDefinitionById(processDefinitionId);

// 删除流程定义
repositoryService.deleteDeployment(deploymentId, true);

4.2 RuntimeService(运行时服务)

管理流程实例和执行:

// 启动流程实例
ProcessInstance processInstance = runtimeService
    .startProcessInstanceByKey("leaveRequest", variables);

// 设置流程变量
runtimeService.setVariable(processInstanceId, "days", 5);
runtimeService.setVariable(processInstanceId, "reason", "休息");

// 获取流程变量
Integer days = (Integer) runtimeService.getVariable(processInstanceId, "days");

// 触发流程执行
runtimeService.trigger(executionId);

// 挂起/激活流程实例
runtimeService.suspendProcessInstanceById(processInstanceId);
runtimeService.activateProcessInstanceById(processInstanceId);

// 删除流程实例
runtimeService.deleteProcessInstance(processInstanceId, "取消申请");

4.3 TaskService(任务服务)

管理用户任务:

// 查询用户的待办任务
List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("zhangsan")
    .orderByTaskCreateTime()
    .desc()
    .list();

// 完成任务
taskService.complete(taskId);

// 带变量完成任务
Map<String, Object> variables = new HashMap<>();
variables.put("approved", true);
taskService.complete(taskId, variables);

// 认领任务(候选任务)
taskService.claim(taskId, "lisi");

// 委派任务
taskService.delegateTask(taskId, "wangwu");

// 设置任务优先级
taskService.setPriority(taskId, 50);

4.4 HistoryService(历史服务)

查询历史数据:

// 查询已完成的流程实例
List<HistoricProcessInstance> finishedInstances = historyService
    .createHistoricProcessInstanceQuery()
    .finished()
    .orderByProcessInstanceEndTime()
    .desc()
    .list();

// 查询历史任务
List<HistoricTaskInstance> historicTasks = historyService
    .createHistoricTaskInstanceQuery()
    .taskAssignee("zhangsan")
    .finished()
    .list();

// 查询历史变量
List<HistoricVariableInstance> variables = historyService
    .createHistoricVariableInstanceQuery()
    .processInstanceId(processInstanceId)
    .list();

// 查询流程实例历史(按时间线)
List<HistoricActivityInstance> activities = historyService
    .createHistoricActivityInstanceQuery()
    .processInstanceId(processInstanceId)
    .orderByHistoricActivityInstanceStartTime()
    .asc()
    .list();

4.5 ManagementService(管理服务)

执行管理操作:

// 获取数据库表信息
TableMetaData tableMetaData = managementService
    .getTablesMetaData()
    .get("ACT_RU_TASK");

// 执行自定义SQL
List<Map<String, Object>> results = managementService
    .executeCustomSql(
        new AbstractCustomSqlExecution<CustomQuery, List<Map<String, Object>>>(CustomQuery.class) {
            @Override
            public List<Map<String, Object>> execute(Configuration configuration) {
                // 自定义SQL执行逻辑
                return null;
            }
        }
    );

// 获取作业列表
List<Job> jobs = managementService.createJobQuery().list();

五、实战案例:请假审批系统

5.1 业务需求

实现一个企业内部请假审批系统,支持以下功能:

  1. 员工提交请假申请
  2. 部门经理审批(1-3天直接通过)
  3. HR审批(超过3天需要HR审批)
  4. 审批通过/驳回
  5. 查询请假记录

5.2 系统架构设计

5.3 流程定义

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:flowable="http://flowable.org/bpmn"
             targetNamespace="Examples">

    <process id="leaveRequest" name="请假审批流程" isExecutable="true">

        <!-- 开始事件 -->
        <startEvent id="startEvent" name="提交申请"/>

        <!-- 员工填写请假单 -->
        <userTask id="submitLeave" name="填写请假单"
                  flowable:assignee="${initiator}">
            <documentation>员工填写请假信息,包括请假天数、原因等</documentation>
        </userTask>

        <!-- 部门经理审批 -->
        <userTask id="managerApproval" name="经理审批"
                  flowable:candidateGroups="managers">
            <documentation>部门经理审批请假申请</documentation>
        </userTask>

        <!-- 排他网关:根据审批结果和天数决定流程走向 -->
        <exclusiveGateway id="approvalGateway"/>

        <!-- 驳回处理 -->
        <serviceTask id="rejectHandler" name="处理驳回"
                     flowable:class="com.example.flowable.delegate.RejectDelegate"/>

        <!-- HR审批(超过3天) -->
        <userTask id="hrApproval" name="HR审批"
                  flowable:candidateGroups="hr">
            <documentation>HR审批长期请假申请</documentation>
        </userTask>

        <!-- 通知员工 -->
        <serviceTask id="notifyEmployee" name="发送通知"
                     flowable:class="com.example.flowable.delegate.NotifyDelegate"/>

        <!-- 结束事件 -->
        <endEvent id="approveEnd" name="审批通过"/>
        <endEvent id="rejectEnd" name="审批驳回"/>

        <!-- 连接线 -->
        <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="submitLeave"/>
        <sequenceFlow id="flow2" sourceRef="submitLeave" targetRef="managerApproval"/>

        <sequenceFlow id="flow3" sourceRef="managerApproval" targetRef="approvalGateway"/>

        <!-- 驳回 -->
        <sequenceFlow id="flow4" sourceRef="approvalGateway" targetRef="rejectHandler">
            <conditionExpression>${approved == false}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow5" sourceRef="rejectHandler" targetRef="notifyEmployee"/>
        <sequenceFlow id="flow6" sourceRef="notifyEmployee" targetRef="rejectEnd"/>

        <!-- 通过但需要HR审批 -->
        <sequenceFlow id="flow7" sourceRef="approvalGateway" targetRef="hrApproval">
            <conditionExpression>${approved == true && days > 3}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow8" sourceRef="hrApproval" targetRef="notifyEmployee"/>
        <sequenceFlow id="flow9" sourceRef="notifyEmployee" targetRef="approveEnd"/>

        <!-- 通过且不需要HR审批 -->
        <sequenceFlow id="flow10" sourceRef="approvalGateway" targetRef="notifyEmployee">
            <conditionExpression>${approved == true && days <= 3}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow11" sourceRef="notifyEmployee" targetRef="approveEnd"/>

    </process>
</definitions>

5.4 服务层实现

请假服务
@Service
public class LeaveRequestService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    /**
     * 创建请假申请
     */
    public LeaveRequest createLeaveRequest(LeaveRequest request) {
        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("initiator", request.getEmployeeId());
        variables.put("days", request.getDays());
        variables.put("reason", request.getReason());
        variables.put("startDate", request.getStartDate());
        variables.put("endDate", request.getEndDate());

        // 启动流程实例
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey("leaveRequest", request.getBusinessKey(), variables);

        // 完成填写请假单任务,自动流转到经理审批
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstance.getId())
                .taskAssignee(request.getEmployeeId())
                .singleResult();

        if (task != null) {
            taskService.complete(task.getId());
        }

        // 保存流程实例ID
        request.setProcessInstanceId(processInstance.getId());
        request.setStatus("pending");

        return request;
    }

    /**
     * 经理审批
     */
    public void managerApproval(String taskId, boolean approved, String comment) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", approved);
        variables.put("managerComment", comment);

        // 添加审批意见
        taskService.addComment(taskId, null, comment);

        // 完成任务
        taskService.complete(taskId, variables);
    }

    /**
     * HR审批
     */
    public void hrApproval(String taskId, boolean approved, String comment) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", approved);
        variables.put("hrComment", comment);

        taskService.addComment(taskId, null, comment);
        taskService.complete(taskId, variables);
    }

    /**
     * 获取用户的待办任务
     */
    public List<TaskDTO> getMyTasks(String userId) {
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee(userId)
                .orderByTaskCreateTime()
                .desc()
                .list();

        return tasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 获取组任务(候选任务)
     */
    public List<TaskDTO> getCandidateTasks(String groupId) {
        List<Task> tasks = taskService.createTaskQuery()
                .taskCandidateGroup(groupId)
                .orderByTaskCreateTime()
                .desc()
                .list();

        return tasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 认领任务
     */
    public void claimTask(String taskId, String userId) {
        taskService.claim(taskId, userId);
    }

    /**
     * 查询请假历史记录
     */
    public List<LeaveRequestHistory> getLeaveHistory(String employeeId) {
        List<HistoricProcessInstance> instances = historyService
                .createHistoricProcessInstanceQuery()
                .variableValueEquals("initiator", employeeId)
                .orderByProcessInstanceStartTime()
                .desc()
                .list();

        return instances.stream()
                .map(this::convertToHistory)
                .collect(Collectors.toList());
    }

    private TaskDTO convertToDTO(Task task) {
        TaskDTO dto = new TaskDTO();
        dto.setTaskId(task.getId());
        dto.setTaskName(task.getName());
        dto.setProcessInstanceId(task.getProcessInstanceId());
        dto.setCreateTime(task.getCreateTime());
        dto.setAssignee(task.getAssignee());

        // 获取流程变量
        Map<String, Object> variables = taskService.getVariables(task.getId());
        dto.setVariables(variables);

        return dto;
    }
}
驳回处理委托
public class RejectDelegate implements JavaDelegate {

    @Override
    public void execute(DelegateExecution execution) {
        String processInstanceId = execution.getProcessInstanceId();
        String initiator = (String) execution.getVariable("initiator");
        String reason = (String) execution.getVariable("reason");

        // 记录驳回原因
        execution.setVariable("rejectReason", "请假申请被驳回");

        // 这里可以发送通知、更新业务系统状态等
        System.out.println("驳回请假申请: " + processInstanceId);
        System.out.println("申请人: " + initiator);
        System.out.println("请假原因: " + reason);

        // 可以调用外部服务发送邮件、短信通知
        // notificationService.sendRejectNotification(initiator);
    }
}
通知委托
public class NotifyDelegate implements JavaDelegate {

    @Override
    public void execute(DelegateExecution execution) {
        String processInstanceId = execution.getProcessInstanceId();
        String initiator = (String) execution.getVariable("initiator");
        Boolean approved = (Boolean) execution.getVariable("approved");

        if (Boolean.TRUE.equals(approved)) {
            System.out.println("审批通过通知: " + processInstanceId);
            // 发送通过通知
        } else {
            System.out.println("审批驳回通知: " + processInstanceId);
            // 发送驳回通知
        }
    }
}

5.5 REST API

@RestController
@RequestMapping("/api/leave")
public class LeaveRequestController {

    @Autowired
    private LeaveRequestService leaveRequestService;

    /**
     * 提交请假申请
     */
    @PostMapping("/submit")
    public ResponseEntity<LeaveRequest> submitLeave(@RequestBody LeaveRequest request) {
        LeaveRequest result = leaveRequestService.createLeaveRequest(request);
        return ResponseEntity.ok(result);
    }

    /**
     * 获取我的待办任务
     */
    @GetMapping("/my-tasks")
    public ResponseEntity<List<TaskDTO>> getMyTasks(@RequestParam String userId) {
        List<TaskDTO> tasks = leaveRequestService.getMyTasks(userId);
        return ResponseEntity.ok(tasks);
    }

    /**
     * 获取候选任务
     */
    @GetMapping("/candidate-tasks")
    public ResponseEntity<List<TaskDTO>> getCandidateTasks(@RequestParam String groupId) {
        List<TaskDTO> tasks = leaveRequestService.getCandidateTasks(groupId);
        return ResponseEntity.ok(tasks);
    }

    /**
     * 认领任务
     */
    @PostMapping("/tasks/{taskId}/claim")
    public ResponseEntity<Void> claimTask(
            @PathVariable String taskId,
            @RequestParam String userId) {
        leaveRequestService.claimTask(taskId, userId);
        return ResponseEntity.ok().build();
    }

    /**
     * 完成审批
     */
    @PostMapping("/tasks/{taskId}/complete")
    public ResponseEntity<Void> completeTask(
            @PathVariable String taskId,
            @RequestBody ApprovalRequest approval) {
        if ("managerApproval".equals(approval.getTaskName())) {
            leaveRequestService.managerApproval(taskId, approval.isApproved(), approval.getComment());
        } else if ("hrApproval".equals(approval.getTaskName())) {
            leaveRequestService.hrApproval(taskId, approval.isApproved(), approval.getComment());
        }
        return ResponseEntity.ok().build();
    }

    /**
     * 查询请假历史
     */
    @GetMapping("/history")
    public ResponseEntity<List<LeaveRequestHistory>> getHistory(@RequestParam String employeeId) {
        List<LeaveRequestHistory> history = leaveRequestService.getLeaveHistory(employeeId);
        return ResponseEntity.ok(history);
    }
}

六、高级特性

6.1 并行网关

并行网关用于处理多个并发任务:

<parallelGateway id="fork"/>
<parallelGateway id="join"/>

<!-- 分支1 -->
<userTask id="task1" name="任务1"/>
<sequenceFlow sourceRef="fork" targetRef="task1"/>
<sequenceFlow sourceRef="task1" targetRef="join"/>

<!-- 分支2 -->
<userTask id="task2" name="任务2"/>
<sequenceFlow sourceRef="fork" targetRef="task2"/>
<sequenceFlow sourceRef="task2" targetRef="join"/>

<!-- 分支3 -->
<userTask id="task3" name="任务3"/>
<sequenceFlow sourceRef="fork" targetRef="task3"/>
<sequenceFlow sourceRef="task3" targetRef="join"/>

6.2 子流程

子流程用于封装可重用的流程片段:

<subProcess id="subProcess" name="审批子流程">
    <startEvent id="subStart"/>
    <userTask id="subTask" name="子流程任务"/>
    <endEvent id="subEnd"/>

    <sequenceFlow sourceRef="subStart" targetRef="subTask"/>
    <sequenceFlow sourceRef="subTask" targetRef="subEnd"/>
</subProcess>

<callActivity id="callSubProcess" name="调用子流程"
               calledElement="subProcess"/>

6.3 事件机制

Flowable支持多种事件类型:

  • 定时器事件:基于时间的触发
  • 消息事件:异步消息传递
  • 信号事件:广播式通知
  • 错误事件:异常处理
<!-- 定时器事件 -->
<intermediateCatchEvent id="timerEvent" name="等待通知">
    <timerEventDefinition>
        <timeDuration>PT2H</timeDuration>
    </timerEventDefinition>
</intermediateCatchEvent>

<!-- 消息事件 -->
<intermediateCatchEvent id="messageEvent" name="接收消息">
    <messageEventDefinition messageRef="approvalMessage"/>
</intermediateCatchEvent>

<!-- 边界定时器事件 -->
<boundaryEvent id="boundaryTimer" attachedToRef="userTask"
               cancelActivity="true">
    <timerEventDefinition>
        <timeDuration>PT1H</timeDuration>
    </timerEventDefinition>
</boundaryEvent>

6.4 监听器

通过监听器实现业务逻辑的扩展:

// 流程启动监听器
public class ProcessStartListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        String processDefinitionId = execution.getProcessDefinitionId();
        System.out.println("流程启动: " + processDefinitionId);

        // 记录日志、发送通知等
    }
}

// 任务创建监听器
public class TaskCreateListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        String taskName = delegateTask.getName();
        String assignee = delegateTask.getAssignee();
        System.out.println("任务创建: " + taskName + ", 分配给: " + assignee);

        // 发送任务通知
    }
}

配置监听器:

<process id="leaveRequest">
    <extensionElements>
        <flowable:executionListener event="start"
            class="com.example.flowable.listener.ProcessStartListener"/>
    </extensionElements>

    <userTask id="managerTask" flowable:assignee="${manager}">
        <extensionElements>
            <flowable:taskListener event="create"
                class="com.example.flowable.listener.TaskCreateListener"/>
        </extensionElements>
    </userTask>
</process>

七、生产环境最佳实践

7.1 数据库优化

-- 为常用查询字段添加索引
CREATE INDEX idx_ru_task_ASSIGNEE ON ACT_RU_TASK(ASSIGNEE_);
CREATE INDEX idx_ru_task_PROC_INST ON ACT_RU_TASK(PROC_INST_ID_);
CREATE INDEX idx_hi_procinst_BUS_KEY ON ACT_HI_PROCINST(BUS_KEY_);
CREATE INDEX idx_hi_actinst_PROC_INST ON ACT_HI_ACTINST(PROC_INST_ID_);

-- 定期清理历史数据(根据业务需求配置保留时长)
DELETE FROM ACT_HI_VARINST WHERE END_TIME_ < DATE_SUB(NOW(), INTERVAL 1 YEAR);
DELETE FROM ACT_HI_DETAIL WHERE TIME_ < DATE_SUB(NOW(), INTERVAL 1 YEAR);

7.2 性能优化

  1. 异步执行:对耗时操作使用异步任务
<serviceTask id="asyncTask" name="异步任务"
             flowable:async="true"
             flowable:class="com.example.flowable.delegate.AsyncTaskDelegate"/>
  1. 批量操作:使用批量查询和操作API
// 批量查询任务
List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("user1")
    .listPage(0, 100);

// 批量完成任务
List<String> taskIds = Arrays.asList("task1", "task2", "task3");
taskService.completeBatchTasks(taskIds);
  1. 缓存配置:启用流程定义缓存
configuration.setProcessDefinitionCacheSize(100);
configuration.setEnableProcessDefinitionInfoCache(true);

7.3 安全配置

// 配置用户权限管理
IdentityService identityService = processEngine.getIdentityService();

// 创建用户
User user = identityService.newUser("zhangsan");
user.setFirstName("三");
user.setLastName("张");
user.setEmail("zhangsan@example.com");
identityService.saveUser(user);

// 创建组
Group group = identityService.newGroup("managers");
group.setName("经理组");
identityService.saveGroup(group);

// 分配用户到组
identityService.createMembership("zhangsan", "managers");

7.4 监控与告警

@Service
public class FlowableMonitorService {

    @Autowired
    private ManagementService managementService;

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 获取运行中的流程统计
     */
    public Map<String, Long> getProcessStatistics() {
        Map<String, Long> stats = new HashMap<>();

        // 各流程运行实例数
        List<ProcessInstance> instances = runtimeService.createProcessInstanceQuery().list();
        Map<String, Long> countByProcess = instances.stream()
            .collect(Collectors.groupingBy(
                ProcessInstance::getProcessDefinitionKey,
                Collectors.counting()
            ));
        stats.putAll(countByProcess);

        // 待办任务统计
        long pendingTasks = managementService.createTaskQuery().count();
        stats.put("pendingTasks", pendingTasks);

        return stats;
    }

    /**
     * 检测异常流程(运行时间过长)
     */
    public List<ProcessInstance> detectLongRunningProcesses(int thresholdHours) {
        Date threshold = new Date(System.currentTimeMillis() - thresholdHours * 3600000L);

        return runtimeService.createProcessInstanceQuery()
            .startedBefore(threshold)
            .list();
    }

    /**
     * 获取数据库表信息
     */
    public Map<String, Object> getDatabaseInfo() {
        Map<String, Object> info = new HashMap<>();

        // 获取各表记录数
        String[] tables = {"ACT_RU_EXECUTION", "ACT_RU_TASK", "ACT_HI_PROCINST"};
        for (String table : tables) {
            long count = managementService.createTablePageQuery()
                .tableName(table)
                .listPage(0, 1)
                .getTotal();
            info.put(table, count);
        }

        return info;
    }
}

八、微服务集成

在微服务架构中使用Flowable:

# application.yml配置
flowable:
  # 数据库配置
  datasource:
    url: jdbc:mysql://localhost:3306/flowable?useSSL=false
    username: flowable
    password: flowable
    driver-class-name: com.mysql.cj.jdbc.Driver

  # 异步执行器配置
  async-executor-activate: true
  async-executor-max-jobs-per-acquisition: 10
  async-executor-default-queue-size: 100

  # REST API配置
  rest:
    enabled: true

  # 邮件服务器配置
  mail:
    server:
      host: smtp.example.com
      port: 587
      username: noreply@example.com
      password: password

服务间通信示例:

@Service
public class WorkflowIntegrationService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 跨服务启动流程
     */
    public void startCrossServiceProcess(WorkflowRequest request) {
        // 调用其他服务获取数据
        UserDTO user = restTemplate.getForObject(
            "http://user-service/api/users/" + request.getUserId(),
            UserDTO.class
        );

        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("user", user);
        variables.put("request", request);

        // 启动流程
        runtimeService.startProcessInstanceByKey(
            "crossServiceProcess",
            request.getBusinessKey(),
            variables
        );
    }

    /**
     * 流程回调处理
     */
    public void handleProcessCallback(String processInstanceId, String eventType) {
        // 根据事件类型执行不同操作
        switch (eventType) {
            case "completed":
                // 流程完成后的处理
                handleProcessCompleted(processInstanceId);
                break;
            case "cancelled":
                // 流程取消后的处理
                handleProcessCancelled(processInstanceId);
                break;
        }
    }
}

九、总结

Flowable作为一款优秀的开源工作流引擎,具有以下优势:

  1. 标准化:完全符合BPMN 2.0标准,学习成本低
  2. 轻量级:可嵌入任何Java应用,部署简单
  3. 高性能:支持高并发场景,适合企业级应用
  4. 灵活扩展:提供丰富的扩展点,易于定制
  5. 社区活跃:文档完善,社区支持良好