1. 概述
Activiti 是一个工作流和业务流程管理系统。我们可以通过其提供的 API 定义流程、执行流程,并以不同方式操作流程。它要求 JDK 7+ 环境。
开发时可在任意 IDE 中进行,但若要使用 Activiti Designer,则需要 Eclipse。
我们可以使用 BPMN 2.0 标准定义流程,还有一种不太流行的方式——使用 Java 类(如 StartEvent
、EndEvent
、UserTask
、SequenceFlow
等)。
若要运行流程或访问任何服务,需创建 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.xml
和 activiti-context.xml
文件:
- 对于
activiti.cfg.xml
:按常规方式创建ProcessEngine
- 对于
activiti-context.xml
:以 Spring 方式创建(构建 Spring 应用上下文并从中获取ProcessEngine
)
流程执行时,所有步骤将按 BPMN 文件定义的顺序执行。
4.1. 流程定义与相关术语
ProcessDefinition
表示业务流程,用于定义流程中各步骤的结构和行为。部署流程定义即将其加载到 Activiti 数据库。
流程定义主要通过 BPMN 2.0 标准定义,也可用 Java 代码实现。本节所有术语均有对应的 Java 类。
启动流程定义后,称为流程实例:
ProcessInstance
是ProcessDefinition
的一次执行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>
条件分支通过 sequenceFlow
的 conditionExpression
实现:
<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
的表单属性
流程逻辑简单粗暴:
- 员工提交请假申请(天数/日期)
- 经理审批(批准/拒绝)
- 批准 → 发送确认邮件(
ServiceTask
) - 拒绝 → 员工选择修改重申或放弃
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());
}
部署后引擎会:
- 解析 BPMN 文件转为可执行内容
- 在仓库表添加部署记录
后续可通过 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. 暂停与激活流程
可暂停 ProcessDefinition
或 ProcessInstance
:
- 暂停
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 开发工作流应用:
- 创建
ProcessEngineConfiguration
配置文件构建ProcessEngine
- 通过引擎访问核心服务(Repository/Runtime/Task 等)
- 实现流程部署、实例启动、任务处理等关键操作
完整示例代码见 GitHub 仓库。