Activiti 7 Workflow Engine: Concepts, Configuration, Deployment, and Operations Guide
This article provides a comprehensive tutorial on Activiti 7, covering workflow concepts, engine configuration files, process engine creation methods, service interfaces, BPMN diagram symbols, deployment techniques, task management, process variables, gateway types, and integration with Spring and Spring Boot.
Concept
A workflow automates business processes by passing documents, information, or tasks among participants according to predefined rules, achieving a business goal.
Activiti 7
Introduction
Activiti is a workflow engine that extracts complex business processes from a system and defines them using BPMN 2.0. It manages process execution, reducing the effort required to modify business logic and improving system robustness.
Before using Activiti, you need to create an activiti.cfg.xml configuration file and add the required dependencies.
<dependencies>
<!-- Core Activiti packages -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>6.0.0</version>
</dependency>
... (other dependencies omitted for brevity) ...
</dependencies>activiti.cfg.xml
The engine configuration file defines ProcessEngineConfiguration , data source, and transaction manager settings.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- DBCP connection pool -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="3"/>
<property name="maxIdle" value="1"/>
</bean>
<!-- Process engine configuration bean (default id is processEngineConfiguration) -->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="databaseSchemaUpdate" value="true"/>
<property name="asyncExecutorActivate" value="false"/>
<property name="mailServerHost" value="mail.my-corp.com"/>
<property name="mailServerPort" value="5025"/>
</bean>
</beans>Process Engine Configuration Class
The ProcessEngineConfiguration class creates a ProcessEngine instance, which is the core of the workflow engine.
Creating the Workflow Engine
Default Creation
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);Custom Creation
// Custom creation
ProcessEngineConfiguration processEngineConfiguration =
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();After the engine is created, Activiti automatically generates 25 tables in the database.
Service Interfaces
Activiti provides several service interfaces for deployment, execution, and management:
RepositoryService : Manage deployment packages and process definitions.
RuntimeService : Query and control running process instances.
TaskService : Manage user tasks.
HistoryService : Access historical execution data.
ManagementService : Engine administration and maintenance.
Process Diagram Symbols
Typical BPMN symbols include Event, Activity, Gateway, and Sequence Flow. An IntelliJ plugin (actiBPM) is recommended for editing BPMN files.
Process Operations
Deploying a Process
Deploy a single BPMN file and its PNG image using RepositoryService :
public void deployment() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.name("Travel Request Process")
.addClasspathResource("bpmn/evection.bpmn")
.addClasspathResource("bpmn/evection.png")
.deploy();
System.out.println("Deployment ID:" + deployment.getId());
System.out.println("Deployment Name:" + deployment.getName());
}Multiple processes can be deployed together using a ZIP archive:
@Test
public void deployProcessByZip() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
InputStream inputStream = this.getClass().getClassLoader()
.getResourceAsStream("bpmn/evection.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("Deployment ID:" + deploy.getId());
System.out.println("Deployment Name:" + deploy.getName());
}Starting a Process Instance
public void startProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");
System.out.println("Definition ID:" + instance.getProcessDefinitionId());
System.out.println("Instance ID:" + instance.getId());
System.out.println("Current Activity ID:" + instance.getActivityId());
}Task Query
@Test
public void findPersonalTaskList() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List
taskList = taskService.createTaskQuery()
.processDefinitionKey("myEvection")
.includeProcessVariables()
.taskAssignee("zhangsan")
.list();
for (Task task : taskList) {
System.out.println("Process Instance ID:" + task.getProcessInstanceId());
System.out.println("Task ID:" + task.getId());
System.out.println("Assignee:" + task.getAssignee());
System.out.println("Task Name:" + task.getName());
}
}Completing a Task
@Test
public void completeTask() {
String key = "testCandidiate";
String assignee = "张三1";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assignee)
.singleResult();
if (task != null) {
taskService.complete(task.getId());
}
}Suspend/Activate Process Instances
All instances of a definition:
@Test
public void suspendAllProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
boolean suspended = processDefinition.isSuspended();
String id = processDefinition.getId();
if (suspended) {
repositoryService.activateProcessDefinitionById(id, true, null);
System.out.println("Process Definition " + id + " activated");
} else {
repositoryService.suspendProcessDefinitionById(id, true, null);
System.out.println("Process Definition " + id + " suspended");
}
}Single instance:
@Test
public void suspendSingleProcessInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceId("17501")
.singleResult();
boolean suspended = instance.isSuspended();
String instanceId = instance.getId();
if (suspended) {
runtimeService.activateProcessInstanceById(instanceId);
System.out.println("Instance " + instanceId + " activated");
} else {
runtimeService.suspendProcessInstanceById(instanceId);
System.out.println("Instance " + instanceId + " suspended");
}
}Process Variables
Objects stored as variables must implement Serializable . Example POJO:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Evection implements Serializable {
private Long id;
private Integer days;
private String evectionName;
private Date startTime;
private Date endTime;
private String address;
private String reason;
}Variables can be set when starting a process:
@Test
public void startProcess() {
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtime = engine.getRuntimeService();
Map
vars = new HashMap<>();
Evection evection = new Evection();
evection.setDays(2);
vars.put("evection", evection);
vars.put("assignee0", "张三");
vars.put("assignee1", "李经理");
vars.put("assignee2", "王财务");
vars.put("assignee3", "赵总经理");
runtime.startProcessInstanceByKey("myProcess_1", vars);
}Or during task completion:
@Test
public void completeTask() {
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = engine.getTaskService();
Evection evection = new Evection();
evection.setDays(2);
Map
vars = new HashMap<>();
vars.put("evection", evection);
Task task = taskService.createTaskQuery()
.processDefinitionKey("myProcess_2")
.taskAssignee("王财务0")
.singleResult();
if (task != null) {
taskService.complete(task.getId(), vars);
}
}Gateways
Exclusive Gateway
Evaluates outgoing conditions and follows the first true branch (lowest ID if multiple are true). Throws an exception if none match.
Parallel Gateway
Splits the flow into multiple parallel branches (fork) and later joins them (join). Conditions on outgoing flows are ignored.
Inclusive Gateway
Combines features of exclusive and parallel gateways: evaluates conditions and can follow multiple true branches in parallel, then waits for all active tokens to arrive before proceeding.
Event Gateway
Used to wait for specific events before continuing the process flow.
Integration with Spring
Spring XML Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/actspring"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="3"/>
<property name="maxIdle" value="1"/>
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>Spring Boot Configuration (application.yml)
spring:
application:
name: actspringboot
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/actspring?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
username: root
password: root
activiti:
database-schema-update: true # true for dev, false for prod
check-process-definitions: false
db-history-used: true
history-level: full
server:
port: 8082Conclusion
The guide demonstrates how to set up Activiti 7, configure the engine, define BPMN processes, manage deployments, start instances, handle tasks, work with variables, use different gateway types, and integrate the engine with both classic Spring XML and Spring Boot environments.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.