Building and Managing an Activiti Workflow Engine for Approval Processes in Java
This article explains how to design, configure, and operate an Activiti workflow engine in a Java Spring Boot application, covering BPMN diagram creation, engine setup, deployment, task handling, code examples, API usage, and comparisons with other workflow solutions.
Introduction
Workflow approval is a core capability of office OA systems, and designing a robust approval process requires careful handling of multiple users, task flows, and branch decisions. Using the Activiti open‑source workflow engine simplifies these complexities.
Designing the Approval Process
The process starts with a BPMN diagram that defines a two‑level supervisor approval flow. The diagram includes a start event, a leave request task, a supervisor task, an exclusive gateway for decision branching, a second‑level supervisor task, and end events for approval success or failure.
Key Steps
Draw the BPMN diagram (e.g., using the ActiBPM plugin for IntelliJ).
Deploy the diagram to the workflow engine.
Start a process instance with variables such as applyUser , supervisor , and upperSupervisor .
Handle tasks for the applicant, first‑level supervisor, and second‑level supervisor, setting variables like result1 and result2 to drive branch decisions.
Engine Setup and Configuration
Activiti requires a data source and engine configuration. The example uses an H2 in‑memory database for quick testing.
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>5.23.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>Spring configuration defines a DataSource bean and a StandaloneProcessEngineConfiguration bean with databaseSchemaUpdate set to true so that Activiti creates its tables automatically.
Code Example: Deploying and Running the Process
@SpringBootTest(classes = {ActivitiStartApplication.class})
public class ActivitiStartApplicationTests {
private static final Logger log = LoggerFactory.getLogger(ActivitiStartApplicationTests.class);
@Autowired
private ApplyTaskListener applyTaskListener;
@Test
void contextLoads() {
System.out.println("启动成功");
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
HistoryService historyService = engine.getHistoryService();
repositoryService.createDeployment().addClasspathResource("processes/apply.bpmn").deploy();
Map
variableMap = new HashMap<>();
variableMap.put("applyUser", "zhang3");
variableMap.put("supervisor", "li4");
variableMap.put("upperSupervisor", "wang5");
ProcessInstance instance = runtimeService.startProcessInstanceByKey("apply_processor_1", variableMap);
// Applicant completes request
Task firstTask = taskService.createTaskQuery().taskAssignee("zhang3").singleResult();
log.warn("用户任务完成,流程ID:{}, 任务名称 :{}, id:{}, assignee:{}",
firstTask.getProcessInstanceId(), firstTask.getName(), firstTask.getId(), firstTask.getAssignee());
taskService.complete(firstTask.getId(), Maps.newHashMap("day", 4));
// First‑level supervisor approves
Task secondTask = taskService.createTaskQuery().taskAssignee("li4").singleResult();
taskService.setVariable(secondTask.getId(), "result1", true);
log.warn("用户任务完成流程ID:{}, 任务名称 :{}, id:{}, assignee:{}",
secondTask.getProcessInstanceId(), secondTask.getName(), secondTask.getId(), secondTask.getAssignee());
taskService.complete(secondTask.getId());
// Second‑level supervisor (if needed)
Task thirdTask = taskService.createTaskQuery().taskAssignee("wang5").singleResult();
if (thirdTask != null) {
taskService.setVariable(thirdTask.getId(), "result2", true);
log.warn("用户任务完成,流程ID:{}, 任务名称:{}, id:{}, assignee:{}",
thirdTask.getProcessInstanceId(), thirdTask.getName(), thirdTask.getId(), thirdTask.getAssignee(), thirdTask.getDelegationState());
taskService.complete(thirdTask.getId());
} else {
log.warn("没有查到二级主管审批任务");
}
// Print execution history
log.warn("流程执行过程如下");
List
activityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(instance.getId()).list();
for (HistoricActivityInstance historicActivityInstance : activityInstanceList) {
log.warn("activityName:{},activityType:{}, assignee:{}, taskId:{}",
historicActivityInstance.getActivityName(), historicActivityInstance.getActivityType(),
historicActivityInstance.getAssignee(), historicActivityInstance.getTaskId());
}
}
}BPMN XML Definition
The full BPMN XML defines process IDs, user tasks with assignee expressions, exclusive gateways, and condition expressions such as #{result1==true} and #{day>3} . This XML is deployed by the RepositoryService.
Workflow Engine API Overview
ProcessEngine : Entry point to obtain other services.
RepositoryService : Deploys and manages process definitions.
RuntimeService : Starts, suspends, and deletes process instances.
TaskService : Queries and completes user tasks.
HistoryService : Retrieves historical execution data.
Comparison with Similar Engines
Activiti is the ancestor of Camunda and Flowable. All three share similar usage steps: define BPMN, deploy, start instances, handle tasks, and monitor execution. The article includes comparison tables and diagrams.
Further Learning Directions
Event types and listeners.
Different task types (user, service, script).
Form management.
Parallel gateways and advanced BPMN constructs.
Performance, ID generation, sharding.
Conclusion
Activiti provides a powerful way to implement multi‑user approval workflows without writing custom branching code. By designing BPMN diagrams and leveraging the engine’s services, developers can add new processes or modify existing ones with minimal code changes, focusing only on front‑end integration.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.