zoukankan      html  css  js  c++  java
  • Flowable流程引擎入门

    Flowable是一个流行的轻量级的采用Java开发的业务流程引擎。通过Flowable流程引擎,我们可以部署BPMN2.0的流程定义(一般为XML文件),通过流程定义创建流程实例,查询和访问流程相关的实例与数据,等等。

    Flowable可以灵活地添加到我们的服务、应用、架构中,可以通过引入Flowable jar包,或者直接使用Flowable的Rest API来进行业务流程引擎的操作。

    Flowable是基于Activity5.0的一个分支开发的,因此内部的很多概念都相似。

    使用

    通过创建一个简单的命令行案例了解如何创建Flowable的流程引擎,我们采用假期请假流程。

    • 员工(employee)发出请假的请求
    • 管理者(manager)同意或拒绝请假请求
    • 我们会模拟把请求注册到外部的系统,发送邮件来通知流程的结果

    1 创建项目,添加maven依赖

    <dependencies>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-engine</artifactId>
                <version>6.4.2</version>
            </dependency>
        <!-- 可以采用MySQL存储,也可以采用H2,看自己的需要 -->
            <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 创建流程的配置文件,holiday-request.bpmn20.xml

    流程对应的BPMN图像为:

     
    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">
    
        <!--
            每一步都需要有一个id属性,标记当前流程的步骤,name是可选的
            当流程开始执行的时候,执行过程会从startEvent开始,跟着sequenceFlow往下走
    
            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 编写代码

    
    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
     * 使用场景:
     * 功能描述:
     */
    public class HolidayRequest {
        public static void main(String[] args) {
            // 首先实例化ProcessEngine,线程安全对象,一般全局只有一个即可,从ProcessEngineConfiguration创建的话,可以调整一些
            // 配置,通常我们会从XML中创建,至少要配置一个JDBC连接
            // 如果是在Spring的配置中,使用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")
    
                    // 如果数据表不存在的时候,自动创建数据表
                    .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    
            // 执行完成后,就可以开始创建我们的流程了
            ProcessEngine processEngine = cfg.buildProcessEngine();
    
            // 使用BPMN 2.0定义process。存储为XML,同时也是可以可视化的。NPMN 2.0标准可以让技术人员与业务人员都
            // 参与讨论业务流程中来
    
            // 部署流程
            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());
    
            // 启动process实例,需要一些初始化的变量,这里我们简单的从Scanner中获取,一般在线上会通过接口传递过来
            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);
    
            // 当创建实例的时候,execution就被创建了,然后放在启动的事件中,这个事件可以从数据库中获取,
            // 用户后续等待这个状态即可
            ProcessInstance processInstance =
                    runtimeService.startProcessInstanceByKey("holidayRequest", variables);
    
            // 在Flowable中数据库的事务对数据一致性起着关键性的作用。
            // 查询和完成任务
    
            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 flowable;
    

    5 运行应用

     
    image.png

    Flowable API

    刚才的代码中,我们涉及到了一些Flowable的API,在开发的时候经常需要与这些API打交道。

    入口点为:ProcessEngine,我们有多种方式来创建它。

    通过ProcessEngine,我们可以获取工作流的不同服务类型,ProcessEngine和服务都是线程安全的,因此我们可以用作单例对象来使用这些服务。

     
    image.png
    // 第一次会初始化和创建一个ProcessEngine,后续调用都会从缓存中直接返回,全局创建一次
    // ProcessEngines.init()与ProcessEngines.destroy(). 初始化和消耗与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();
    
    • RepositoryService: 操作和管理流程的定义和部署,deployment(部署)是ProcessEngine的基本单元
    • RuntimeService:每一个流程都可以创建许多的运行实例,RuntimeService启动流程的实例,检索和存储实例的变量信息
    • IdentityService:管理组和用户的身份认证信息
    • FormService:可选的服务
    • HistoryService:检索ProcessEngine的历史数据
    • ManagementService:检索数据库的元数据和表的信息,在编程的时候一般用不到
    • DynamicBpmnService:动态的改变流程的定义,并且不需要重新部署,在生产环境很少使用

    最后

    本次主要运行了一个Flowable的简单应用,介绍了Flowable是什么,在Activiti之上fork的流程引擎。



    作者:Real_man
    链接:https://www.jianshu.com/p/4253f6eac920
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    86. Partition List
    328. Odd Even Linked List
    19. Remove Nth Node From End of List(移除倒数第N的结点, 快慢指针)
    24. Swap Nodes in Pairs
    2. Add Two Numbers(2个链表相加)
    92. Reverse Linked List II(链表部分反转)
    109. Convert Sorted List to Binary Search Tree
    138. Copy List with Random Pointer
    为Unity的新版ugui的Prefab生成预览图
    ArcEngine生成矩形缓冲区
  • 原文地址:https://www.cnblogs.com/javalinux/p/15210343.html
Copyright © 2011-2022 走看看