Backend Development 26 min read

Mastering Activiti: Build Scalable Workflow Engines in Minutes

This article walks you through designing, deploying, and managing a multi‑level approval workflow using the Activiti engine, covering BPMN diagram creation, Spring Boot integration, database schema, API usage, code examples, and best practices for extending processes without additional code.

macrozheng
macrozheng
macrozheng
Mastering Activiti: Build Scalable Workflow Engines in Minutes

Why Use a Workflow Engine?

Workflow approval is a core capability of office OA systems, involving multiple users, task handoffs, and branching. Without a powerful engine, extending or adding new processes becomes cumbersome and error‑prone.

Activiti simplifies this by handling process execution and branch decisions automatically.

Creating a Simple Leave Approval Process

Step 1: Design the BPMN Diagram

Use the ActiBPM plugin for IntelliJ IDEA to draw a diagram that models a two‑level approval: first‑level supervisor approves, and if the leave exceeds three days, a second‑level supervisor approves.

First‑level supervisor approval

Second‑level supervisor approval (if >3 days)

Leave approval BPMN diagram
Leave approval BPMN diagram

Deploy the Diagram

<code>// Create workflow engine
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// Deploy BPMN file
RepositoryService repositoryService = engine.getRepositoryService();
repositoryService.createDeployment().addClasspathResource("processes/apply.bpmn").deploy();</code>

The deployment code runs in the backend; no additional Java code is needed after the diagram is uploaded.

Start a Process Instance

<code>Map<String, Object> variableMap = new HashMap<>();
variableMap.put("applyUser", "zhang3");
variableMap.put("supervisor", "li4");
variableMap.put("upperSupervisor", "wang5");
ProcessInstance instance = runtimeService.startProcessInstanceByKey("apply_processor_1", variableMap);
</code>

This creates a new instance with the applicant and supervisors set as process variables.

Task Handling

The applicant submits a leave request, which creates a task for the first‑level supervisor:

<code>Task firstTask = taskService.createTaskQuery().taskAssignee("zhang3").singleResult();
taskService.complete(firstTask.getId(), Maps.newHashMap("day", 4));
</code>

After completion, the engine evaluates the exclusive gateway condition

#{day>3}

to decide whether to route to the second‑level supervisor.

Second‑Level Approval

<code>Task secondTask = taskService.createTaskQuery().taskAssignee("li4").singleResult();
taskService.setVariable(secondTask.getId(), "result1", true);
taskService.complete(secondTask.getId());
</code>

If the leave exceeds three days, a second task is created for the upper supervisor:

<code>Task thirdTask = taskService.createTaskQuery().taskAssignee("wang5").singleResult();
if (thirdTask != null) {
    taskService.setVariable(thirdTask.getId(), "result2", true);
    taskService.complete(thirdTask.getId());
}
</code>

The engine then proceeds to the final approval or rejection endpoints based on the variables

${result1}

and

${result2}

.

Viewing Execution History

<code>List<HistoricActivityInstance> 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());
}
</code>

This prints a complete audit trail of every node the process passed through.

Activiti Project Configuration

Dependency

<code>&lt;dependency&gt;
    &lt;groupId&gt;org.activiti&lt;/groupId&gt;
    &lt;artifactId&gt;activiti-spring-boot-starter-basic&lt;/artifactId&gt;
    &lt;version&gt;5.23.0&lt;/version&gt;
&lt;/dependency&gt;
</code>

DataSource (H2 for learning)

<code>&lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"&gt;
    &lt;property name="driverClassName" value="org.h2.Driver"/&gt;
    &lt;property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;mode=MySQL;"/&gt;
&lt;/bean&gt;
&lt;bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"&gt;
    &lt;property name="dataSource" ref="dataSource"/&gt;
    &lt;property name="databaseSchemaUpdate" value="true"/&gt;
&lt;/bean&gt;
&lt;context:component-scan base-package="com.muppet.activiti"/&gt;
</code>

H2 Dependency

<code>&lt;dependency&gt;
    &lt;groupId&gt;com.h2database&lt;/groupId&gt;
    &lt;artifactId&gt;h2&lt;/artifactId&gt;
    &lt;scope&gt;runtime&lt;/scope&gt;
&lt;/dependency&gt;
</code>

Database Tables Used by Activiti

ACT_RE_* – process definitions and static resources

ACT_RU_* – runtime data such as tasks, process instances, variables

ACT_HI_* – historic data for audit and reporting

ACT_ID_* – user, group, and permission information

Other tables – event logs, jobs, timers for asynchronous handling

Core API Overview

ProcessEngine

: entry point to obtain other services

RepositoryService

: deploy and manage process definitions

RuntimeService

: start, suspend, or delete process instances

TaskService

: query, claim, and complete tasks

HistoryService

: query completed tasks and historic process data

What Is BPMN?

BPMN (Business Process Modeling Notation) is a standard visual language for describing business processes, enabling clear communication across departments.

Activiti implements BPMN 2.0 and provides a community‑driven, Apache‑licensed engine.

Sample BPMN XML (Leave Process)

<code>&lt;definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" ...&gt;
  &lt;process id="apply_processor_1" isExecutable="true"&gt;
    &lt;startEvent id="_4" name="开始"&gt;
      &lt;extensionElements&gt;
        &lt;activiti:executionListener class="com.muppet.activiti.listener.ApplyTaskListener" event="end"/&gt;
      &lt;/extensionElements&gt;
    &lt;/startEvent&gt;
    &lt;userTask id="_5" name="请假申请" activiti:assignee="#{applyUser}"/&gt;
    &lt;userTask id="_6" name="主管审批" activiti:assignee="${supervisor}"&gt;
      &lt;extensionElements&gt;
        &lt;activiti:executionListener class="com.muppet.activiti.listener.ApplyTaskListener" event="end"/&gt;
      &lt;/extensionElements&gt;
    &lt;/userTask&gt;
    &lt;exclusiveGateway id="_7" name="一级审批结果"/&gt;
    &lt;endEvent id="_8" name="审批不通过"/&gt;
    ... (remaining BPMN elements omitted for brevity) ...
  &lt;/process&gt;
&lt;/definitions&gt;
</code>

Comparing Similar Engines

Camunda and Flowable are both derived from Activiti and share a similar usage flow.

Camunda vs Flowable vs Activiti
Camunda vs Flowable vs Activiti

Typical 5‑Step Workflow

Define BPMN diagram with a modeling tool.

Deploy the diagram to the workflow engine.

Start a new process instance.

Execute tasks; the engine creates tasks and assigns them.

Listen to events and monitor execution via provided APIs.

Further Learning Topics

Event types and listeners.

Different task types: user, service, script.

Form management.

Gateways (parallel, exclusive, etc.).

Performance, scaling, ID generation, sharding.

Conclusion

Activiti is ideal for multi‑user, multi‑step business processes.

Development consists of diagram design, deployment, and instance management.

Adding new processes rarely requires extra Java code—only front‑end forms and simple back‑end endpoints.

For a complete microservice project built with Spring Cloud, Kubernetes, and Activiti, see the mall‑swarm repository and its video tutorials.

JavamicroservicesBPMNSpring BootActivitiWorkflow Engine
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.