Backend Development 28 min read

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.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Activiti 7 Workflow Engine: Concepts, Configuration, Deployment, and Operations Guide

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: 8082

Conclusion

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.

JavaWorkflowdeploymentBPMNSpringActivitiProcessEngine
Code Ape Tech Column
Written by

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

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.