Introduction to Flowable process engine

Article from: https://www.jianshu.com/p/4253f6eac920

Flowable is a popular lightweight business process engine developed in Java. Through the flowable process engine, we can deploy BPMN 2 0 (generally XML file), create process instances through process definitions, query and access process related instances and data, and so on.

Flowable can be flexibly added to our services, applications and architectures. You can operate the business process engine by introducing Flowable jar package or directly using flowable's Rest API.

Flowable is based on activity5 0, so many internal concepts are similar.

use

By creating a simple command line case to understand how to create a Flowable process engine, we adopt the leave process.

  • The employee sends a request for leave
  • The manager agrees or rejects the request for leave
  • We will simulate registering the request with an external system and send an email to notify the result of the process

1 create a project and add maven dependency

 

<dependencies>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-engine</artifactId>
            <version>6.4.2</version>
        </dependency>
    <!-- Can use MySQL Storage can also be used H2,Look at your needs -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.176</version>
        </dependency>
</dependencies>

2. Create a process configuration file, holiday request bpmn20. xml

The BPMN image corresponding to the process is:

getting.started.bpmn.process

 

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             xmlns:flowable="http://flowable.org/bpmn"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">

    <!--
        Each step requires a id Attribute to mark the steps of the current process, name Is optional
        When the process starts to execute, the execution process will start from startEvent Start, follow sequenceFlow Go down

        startEvent -> approveTask -> approved -> externalSystemCall -> holidayApprovedTask -> assign:employee -> approveEnd
                                  -> reject -> sendRejectionMail -> rejectEnd
      -->

    <process id="holidayRequest" name="Holiday Request" isExecutable="true">

        <startEvent id="startEvent"/>
        <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>

        <userTask id="approveTask" name="Approve or reject request" flowable:candidateGroups="managers"/>
        <sequenceFlow sourceRef="approveTask" targetRef="decision"/>

        <exclusiveGateway id="decision"/>
        <sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[
                 ${approved}
              ]]>
            </conditionExpression>
        </sequenceFlow>
        <sequenceFlow  sourceRef="decision" targetRef="sendRejectionMail">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[
                 ${!approved}
               ]]>
            </conditionExpression>
        </sequenceFlow>

        <serviceTask id="externalSystemCall" name="Enter holidays in external system"
                     flowable:class="me.aihe.jmxdemo.flowable.CallExternalSystemDelegate"/>
        <sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>

        <userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>
        <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>

        <serviceTask id="sendRejectionMail" name="Send out rejection email"
                     flowable:class="org.flowable.SendRejectionMail"/>
        <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>

        <endEvent id="approveEnd"/>

        <endEvent id="rejectEnd"/>

    </process>

</definitions>

3 write code

 

import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 * @author he.ai aihehe123@gmail.com
 * Usage scenario:
 * Function Description:
 */
public class HolidayRequest {
    public static void main(String[] args) {
        // First, instantiate ProcessEngine and thread safety object. Generally, there is only one global object. If you create it from ProcessEngineConfiguration, you can adjust some
        // Configuration, which is usually created from XML. At least one JDBC connection must be configured
        // If it is in Spring configuration, use SpringProcessEngineConfiguration

        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
//                .setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1")
//                .setJdbcDriver("org.h2.Driver")
//                .setJdbcUsername("sa")
                .setJdbcPassword("")
                .setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8")
                .setJdbcUsername("aihe")
                .setJdbcPassword("123456")
                .setJdbcDriver("com.mysql.jdbc.Driver")

                // If the data table does not exist, the data table will be created automatically
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

        // After execution, we can start to create our process
        ProcessEngine processEngine = cfg.buildProcessEngine();

        // Define the process using BPMN 2.0. It is stored as XML and can be visualized at the same time. NPMN 2.0 standard enables both technicians and business personnel to
        // Participate in the discussion of business processes

        // Deployment process
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("holiday-request.bpmn20.xml")
                .deploy();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployment.getId())
                .singleResult();
        System.out.println("Found process definition : " + processDefinition.getName());

        // To start the process instance, you need some initialization variables. Here we simply get them from Scanner, and they are generally passed through the interface online
        Scanner scanner= new Scanner(System.in);

        System.out.println("Who are you?");
        String employee = scanner.nextLine();

        System.out.println("How many holidays do you want to request?");
        Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());

        System.out.println("Why do you need them?");
        String description = scanner.nextLine();

        RuntimeService runtimeService = processEngine.getRuntimeService();

        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("employee", employee);
        variables.put("nrOfHolidays", nrOfHolidays);
        variables.put("description", description);

        // When an instance is created, the execution is created and placed in the start event, which can be obtained from the database,
        // Users can wait for this status later
        ProcessInstance processInstance =
                runtimeService.startProcessInstanceByKey("holidayRequest", variables);

        // In Flowable, database transactions play a key role in data consistency.
        // Query and complete tasks

        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
        System.out.println("You have " + tasks.size() + " tasks:");
        for (int i=0; i<tasks.size(); i++) {
            System.out.println((i+1) + ") " + tasks.get(i).getName());
        }


        System.out.println("Which task would you like to complete?");
        int taskIndex = Integer.valueOf(scanner.nextLine());
        Task task = tasks.get(taskIndex - 1);
        Map<String, Object> processVariables = taskService.getVariables(task.getId());
        System.out.println(processVariables.get("employee") + " wants " +
                processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?");

        boolean approved = scanner.nextLine().toLowerCase().equals("y");
        variables = new HashMap<String, Object>();
        variables.put("approved", approved);
        taskService.complete(task.getId(), variables);


        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricActivityInstance> activities =
                historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstance.getId())
                        .finished()
                        .orderByHistoricActivityInstanceEndTime().asc()
                        .list();

        for (HistoricActivityInstance activity : activities) {
            System.out.println(activity.getActivityId() + " took "
                    + activity.getDurationInMillis() + " milliseconds");
        }
    }
}

 

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;

public class CallExternalSystemDelegate implements JavaDelegate {

    public void execute(DelegateExecution execution) {
        System.out.println("Calling the external system for employee "
                + execution.getVariable("employee"));
    }

}

4 create database

 

create database flowable;

5 running applications

 

image.png

Flowable API

In the code just now, we have involved some Flowable APIs. We often need to deal with these APIs during development.

The entry point is: ProcessEngine. There are many ways to create it.

Through ProcessEngine, we can obtain different service types of workflow. ProcessEngine and services are thread safe, so we can use these services as singleton objects.

image.png

 

// For the first time, a ProcessEngine will be initialized and created, and subsequent calls will be directly returned from the cache. It will be created globally
// ProcessEngines.init() and processengines destroy().  Initialization and consumption with processengines
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
  • Repository service: the definition and deployment of operation and management processes. Deployment is the basic unit of process engine
  • RuntimeService: each process can create many running instances. RuntimeService starts the instance of the process and retrieves and stores the variable information of the instance
  • IdentityService: manages the identity authentication information of groups and users
  • FormService: optional service
  • HistoryService: retrieve the historical data of ProcessEngine
  • ManagementService: retrieve the metadata and table information of the database, which is generally not used in programming
  • Dynamic bpmnservice: it changes the definition of process dynamically and does not need to be redeployed. It is rarely used in production environment

last

This time, we mainly run a simple application of Flowable, which introduces what Flowable is and the process engine of fork on Activiti.



Author: Real_man
Link: https://www.jianshu.com/p/4253f6eac920
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.

Added by miro_igov on Sun, 30 Jan 2022 08:46:08 +0200