1. 概述

Activiti 是一个工作流和业务流程管理系统。我们可以通过其提供的 API 定义流程、执行流程,并以不同方式操作流程。它要求 JDK 7+ 环境。

开发时可在任意 IDE 中进行,但若要使用 Activiti Designer,则需要 Eclipse。

我们可以使用 BPMN 2.0 标准定义流程,还有一种不太流行的方式——使用 Java 类(如 StartEventEndEventUserTaskSequenceFlow 等)。

若要运行流程或访问任何服务,需创建 ProcessEngineConfiguration。通过 ProcessEngineConfiguration 可获取 ProcessEngine,后续我们将讨论具体方式。ProcessEngine 是执行工作流和 BPMN 操作的核心入口。

2. Maven 依赖

使用该 API 需添加 Activiti 依赖:

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-engine</artifactId>
</dependency>

3. 创建 ProcessEngine

Activiti 中的 ProcessEngine 通常通过 XML 文件 activiti.cfg.xml 配置。示例配置如下:

<beans xmlns="...">
    <bean id="processEngineConfiguration" class=
      "org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcUrl" 
          value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
        <property name="jdbcDriver" value="org.h2.Driver" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="" />
        <property name="databaseSchemaUpdate" value="true" />
    </bean>
</beans>

现在可通过 ProcessEngines 类获取 ProcessEngine

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

此语句会在类路径下查找 activiti.cfg.xml 文件,并根据配置构建 ProcessEngine

配置文件本质是 Spring 风格的配置,但这不意味着只能在 Spring 环境中使用 Activiti——Spring 能力仅用于内部创建 ProcessEngine

写个 JUnit 测试验证配置:

@Test
public void givenXMLConfig_whenGetDefault_thenGotProcessEngine() {
    ProcessEngine processEngine 
      = ProcessEngines.getDefaultProcessEngine();
    assertNotNull(processEngine);
    assertEquals("root", processEngine.getProcessEngineConfiguration()
      .getJdbcUsername());
}

4. Activiti 流程引擎 API 与服务

API 的交互入口是 ProcessEngine。通过它可访问提供工作流/BPMN 方法的各种服务。ProcessEngine 及所有服务对象都是线程安全的。

ProcessEngines 类会扫描 activiti.cfg.xmlactiviti-context.xml 文件:

  • 对于 activiti.cfg.xml:按常规方式创建 ProcessEngine
  • 对于 activiti-context.xml:以 Spring 方式创建(构建 Spring 应用上下文并从中获取 ProcessEngine

流程执行时,所有步骤将按 BPMN 文件定义的顺序执行。

4.1. 流程定义与相关术语

ProcessDefinition 表示业务流程,用于定义流程中各步骤的结构和行为。部署流程定义即将其加载到 Activiti 数据库。

流程定义主要通过 BPMN 2.0 标准定义,也可用 Java 代码实现。本节所有术语均有对应的 Java 类。

启动流程定义后,称为流程实例

  • ProcessInstanceProcessDefinition 的一次执行
  • StartEvent 关联每个业务流程,表示流程入口点
  • EndEvent 表示流程终点,可定义条件

开始和结束之间的所有步骤称为任务(Tasks),常见类型:

  • ✅ **UserTask**:需用户手动执行的任务
  • ✅ **ServiceTask**:配置代码块,执行到该步骤时自动运行代码

SequenceFlows 连接任务,通过源/目标元素定义,也可设置条件创建分支路径。

4.2. 核心服务

Activiti 提供以下关键服务:

服务名 功能说明
RepositoryService 管理流程定义的部署,处理流程定义相关的静态数据
RuntimeService 管理 ProcessInstance(运行中流程)及流程变量
TaskService 跟踪 UserTask,支持创建/认领/完成任务、操作执行人等
FormService 可选服务,定义流程中的启动表单和任务表单
IdentityService 管理用户(Users)和组(Groups)
HistoryService 记录引擎历史,可设置不同历史级别
ManagementService 处理元数据,开发时通常不需要
DynamicBpmnService 无需重新部署即可动态修改流程

5. 使用 Activiti 服务实战

以"员工请假申请"流程为例学习服务使用:

请假申请流程图

BPMN 2.0 文件 VacationRequest.bpmn20.xml 的开始事件定义:

<startEvent id="startEvent" name="request" 
  activiti:initiator="employeeName">
    <extensionElements>
        <activiti:formProperty id="numberOfDays" 
          name="Number of days" type="long" required="true"/>
        <activiti:formProperty id="startDate" 
          name="Vacation start date (MM-dd-yyyy)" type="date" 
          datePattern="MM-dd-yyyy hh:mm" required="true"/>
        <activiti:formProperty id="reason" name="Reason for leave" 
          type="string"/>
     </extensionElements>
</startEvent>

分配给用户组 "management" 的第一个用户任务:

<userTask id="handle_vacation_request" name=
  "Handle Request for Vacation">
    <documentation>${employeeName} would like to take ${numberOfDays} day(s)
      of vacation (Motivation: ${reason}).</documentation>
    <extensionElements>
        <activiti:formProperty id="vacationApproved" name="Do you approve
          this vacation request?" type="enum" required="true"/>
        <activiti:formProperty id="comments" name="Comments from Manager"
          type="string"/>
    </extensionElements>
    <potentialOwner>
      <resourceAssignmentExpression>
        <formalExpression>management</formalExpression>
      </resourceAssignmentExpression>
    </potentialOwner>
</userTask>

ServiceTask 需指定执行的 Java 类:

<serviceTask id="send-email-confirmation" name="Send email confirmation" 
  activiti:class=
  "com.example.activiti.servicetasks.SendEmailServiceTask.java">
</serviceTask>

条件分支通过 sequenceFlowconditionExpression 实现:

<sequenceFlow id="flow3" name="approved" 
  sourceRef="sid-12A577AE-5227-4918-8DE1-DC077D70967C" 
  targetRef="send-email-confirmation">
    <conditionExpression xsi:type="tFormalExpression">
      <![CDATA[${vacationApproved == 'true'}]]>
    </conditionExpression>
</sequenceFlow>

⚠️ vacationApproved 是上述 UserTask 的表单属性

流程逻辑简单粗暴:

  1. 员工提交请假申请(天数/日期)
  2. 经理审批(批准/拒绝)
  3. 批准 → 发送确认邮件(ServiceTask
  4. 拒绝 → 员工选择修改重申或放弃

ServiceTask 对应的 Java 类需继承 JavaDelegate 并重写 execute() 方法:

public class SendEmailServiceTask implements JavaDelegate {
    public void execute(DelegateExecution execution) {
        // 邮件发送逻辑
    }
}

5.1. 部署流程

让 Activiti 引擎识别流程需先部署。通过 RepositoryService 编程实现:

@Test 
public void givenBPMN_whenDeployProcess_thenDeployed() {
    ProcessEngine processEngine 
      = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService 
      = processEngine.getRepositoryService();
    repositoryService.createDeployment()
      .addClasspathResource(
      "org/activiti/test/vacationRequest.bpmn20.xml")
      .deploy();
    Long count=repositoryService.createProcessDefinitionQuery().count();
    assertEquals("1", count.toString());
}

部署后引擎会:

  1. 解析 BPMN 文件转为可执行内容
  2. 在仓库表添加部署记录

后续可通过 RepositoryService 查询已部署的流程定义。

5.2. 启动流程实例

部署 ProcessDefinition 后,通过创建 ProcessInstance 执行流程:

  • ProcessDefinition 是蓝图
  • ProcessInstance 是运行时实例

单个 ProcessDefinition 可有多个 ProcessInstance,通过 RuntimeService 管理。

启动时需传入流程变量(如请假天数/日期),示例:

@Test
public void givenDeployedProcess_whenStartProcessInstance_thenRunning() {
    // 部署流程定义(省略)    
    Map<String, Object> variables = new HashMap<>();
    variables.put("employeeName", "John");
    variables.put("numberOfDays", 4);
    variables.put("vacationMotivation", "I need a break!");
    
    RuntimeService runtimeService = processEngine.getRuntimeService();
    ProcessInstance processInstance = runtimeService
      .startProcessInstanceByKey("vacationRequest", variables);
    Long count=runtimeService.createProcessInstanceQuery().count();
 
    assertEquals("1", count.toString());
}

💡 多个流程实例通过流程变量区分

启动后可通过 RuntimeService 查询实例信息。

5.3. 完成任务

流程启动后,第一步是分配给 "management" 组的 UserTask。用户需在收件箱完成任务以推进流程。

通过 TaskService 查询并完成任务:

@Test 
public void givenProcessInstance_whenCompleteTask_thenGotNextTask() {
    // 部署流程并启动实例(省略)   
    TaskService taskService = processEngine.getTaskService();
    List<Task> tasks = taskService.createTaskQuery()
      .taskCandidateGroup("management").list();
    Task task = tasks.get(0);
    
    Map<String, Object> taskVariables = new HashMap<>();
    taskVariables.put("vacationApproved", "false");
    taskVariables.put("comments", "We have a tight deadline!");
    taskService.complete(task.getId(), taskVariables);

    Task currentTask = taskService.createTaskQuery()
      .taskName("Modify vacation request").singleResult();
    assertNotNull(currentTask);
}

complete() 方法接收流程变量(此处传入经理的审批结果)

完成后引擎推进到下一步——员工选择是否修改重申。当前流程实例停留在名为 "Modify vacation request" 的 UserTask

5.4. 暂停与激活流程

可暂停 ProcessDefinitionProcessInstance

  • 暂停 ProcessDefinition:期间无法创建新实例
  • 暂停 ProcessInstance:暂停运行中实例

通过 RepositoryService 暂停流程定义:

@Test(expected = ActivitiException.class)
public void givenDeployedProcess_whenSuspend_thenNoProcessInstance() {
    // 部署流程定义(省略)
    repositoryService.suspendProcessDefinitionByKey("vacationRequest");
    runtimeService.startProcessInstanceByKey("vacationRequest"); // 抛出异常
}    

重新激活调用 repositoryService.activateProcessDefinitionXXX 方法。

通过 RuntimeService 暂停流程实例:

runtimeService.suspendProcessInstanceById(processInstance.getId());

6. 总结

本文介绍了如何使用 Activiti 与 Java 开发工作流应用:

  1. 创建 ProcessEngineConfiguration 配置文件构建 ProcessEngine
  2. 通过引擎访问核心服务(Repository/Runtime/Task 等)
  3. 实现流程部署、实例启动、任务处理等关键操作

完整示例代码见 GitHub 仓库


原始标题:A Guide to Activiti with Java | Baeldung

« 上一篇: Apache Maputils 用法