Flowable流程引擎

Flowable流程引擎

Flowable简介

Flowable是什么

官网地址:https://www.flowable.org/

github地址:https://github.com/flowable

Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等。

Flowable与Activiti

Flowable项目源自于Activiti,通过两个框架的发展史即知。在2016.7~2017.5期间Activiti团队内部已经产生了重大的分歧,于是原班核心人员(Activiti5以及6比较核心的leader)Tijs Rademakers和Joram Barrez等便去开发Flowable框架了,原来的Activiti6以及Activiti5代码则留给 Salaboy团队进行开发和维护。Flowable是基于Activiti-6.0.0.Beta4分支开发的。目前Flowable已经修复了Activiti6很多的bug,可以实现零成本从Activiti迁移到Flowable。

image

第一个应用

Spring Boot 整合 Flowable

Spring Boot 提倡约定大于配置。要开始工作,只需在项目中添加flowable-spring-boot-starter依赖,另外Flowable还需要数据库来存储数据。我这里使用mysql + jpa,当然也可以使用H2数据库或者其他数据库。maven配置:

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.6.0</version>
</dependency>

接下来创建对应的数据库,配置数据源:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flowable?serverTimezone=Asia/Shanghai&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    open-in-view: true

以上步骤就是最简单的整合方法了。
运行项目,Flowable创建一系列的数据库表(对应表的用途说明请看文末附件),那就代表整合成功了。

部署流程模型

这里用学生请假流程做例子,首先由学生发起请假申请,然后由老师进行审核,老师审核结束后进行判断:
1.如果请假天数大于2天,流转到校长处审核,然后流程结束。
2.如果请假天数不大于2天,流程结束。

部署流程需要一个.bpmn20.xml文件,可用手动编辑,也可以借助一些工具创建Flowable ModelerFlowable 提供的Web模型编辑工具Eclipse IDE 插件等等

<?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:flowable="http://flowable.org/bpmn" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
  <process id="StudentLeave" name="学生请假流程" isExecutable="true">
    <startEvent id="start" name="开始" flowable:formFieldValidation="true"></startEvent>
    <userTask id="apply" name="请假申请" flowable:assignee="${studentUser}" flowable:formFieldValidation="true">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="teacherPass" name="老师审批" flowable:candidateGroups="teacher" flowable:formFieldValidation="true"></userTask>
    <exclusiveGateway id="judgeTask" name="判断是否大于2天"></exclusiveGateway>
    <endEvent id="end" name="结束"></endEvent>
    <userTask id="principalPass" name="校长审批" flowable:candidateGroups="principal" flowable:formFieldValidation="true"></userTask>
    <sequenceFlow id="principalCheck" name="通过" sourceRef="principalPass" targetRef="end">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="principalNotPassFlow" name="驳回" sourceRef="principalPass" targetRef="apply">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="teacherPassFlow" name="通过" sourceRef="teacherPass" targetRef="judgeTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="teacherNotPassFlow" name="驳回" sourceRef="teacherPass" targetRef="apply">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="startFlow" sourceRef="start" name="流程开始" targetRef="apply"></sequenceFlow>
    <sequenceFlow id="applyFlow" sourceRef="apply" name="申请流程" targetRef="teacherPass"></sequenceFlow>
    <sequenceFlow id="judgeLess" name="小于2天" sourceRef="judgeTask" targetRef="end">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day <= 2}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="judgeMore" name="大于2天" sourceRef="judgeTask" targetRef="principalPass">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day > 2}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_StudentLeave">
    <bpmndi:BPMNPlane bpmnElement="StudentLeave" id="BPMNPlane_StudentLeave">
      <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="apply" id="BPMNShape_apply">
        <omgdc:Bounds height="80.0" width="100.00000000000003" x="229.9708609547486" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="teacherPass" id="BPMNShape_teacherPass">
        <omgdc:Bounds height="80.0" width="99.99999999999994" x="436.9446358140222" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
        <omgdc:Bounds height="40.0" width="40.0" x="645.0" y="158.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
        <omgdc:Bounds height="28.0" width="28.0" x="795.0" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="principalPass" id="BPMNShape_principalPass">
        <omgdc:Bounds height="80.0" width="100.0" x="615.0" y="280.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
        <omgdi:waypoint x="684.5095911949685" y="178.43356643356645"></omgdi:waypoint>
        <omgdi:waypoint x="795.0000829380081" y="178.04860604497966"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="principalNotPassFlow" id="BPMNEdge_principalNotPassFlow">
        <omgdi:waypoint x="615.0" y="320.0"></omgdi:waypoint>
        <omgdi:waypoint x="279.9708609547486" y="320.0"></omgdi:waypoint>
        <omgdi:waypoint x="279.9708609547486" y="217.95000000000002"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
        <omgdi:waypoint x="665.4326241134752" y="197.51043586109145"></omgdi:waypoint>
        <omgdi:waypoint x="665.1411660777385" y="280.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="teacherNotPassFlow" id="BPMNEdge_teacherNotPassFlow">
        <omgdi:waypoint x="486.9446358140222" y="138.0"></omgdi:waypoint>
        <omgdi:waypoint x="486.9446358140222" y="98.8874737106014"></omgdi:waypoint>
        <omgdi:waypoint x="279.9708609547486" y="98.8874737106014"></omgdi:waypoint>
        <omgdi:waypoint x="279.9708609547486" y="138.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="principalCheck" id="BPMNEdge_principalCheck">
        <omgdi:waypoint x="714.9499999999886" y="319.64664310954066"></omgdi:waypoint>
        <omgdi:waypoint x="806.5" y="319.0"></omgdi:waypoint>
        <omgdi:waypoint x="808.7518112709728" y="191.94785201600882"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="applyFlow" id="BPMNEdge_applyFlow">
        <omgdi:waypoint x="329.9208609546613" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="436.9446358140222" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="teacherPassFlow" id="BPMNEdge_teacherPassFlow">
        <omgdi:waypoint x="536.8946358140222" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="645.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="startFlow" id="BPMNEdge_startFlow">
        <omgdi:waypoint x="129.94999932842546" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="229.970860954748" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

将xml保存为生请假流程.bpmn20.xml复制到项目resources/processes目录下,如果没有processes文件夹就自己创建一个,Flowable会自动部署processes目录下的流程模型。启动项目后可以通过RepositoryService查询已经部署的模型,若查询结果不为空就代表模型部署成功了。

@Autowired
    private RepositoryService repositoryService;

    @GetMapping
    public List<String> list() {
        List<ProcessDefinition> processList = repositoryService.createProcessDefinitionQuery().list();
        return processList.stream().map(ProcessDefinition::getName).collect(Collectors.toList());
    }

测试流程

@SpringBootTest
@RunWith(SpringRunner.class)
public class StudentLeaveTest {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Test
    public void test() {

        // 发起请假
        Map<String, Object> map = new HashMap<>();
        map.put("day", 2);
        map.put("studentUser", "小明");
        ProcessInstance studentLeave = runtimeService.startProcessInstanceByKey("StudentLeave", map);
        Task task = taskService.createTaskQuery().processInstanceId(studentLeave.getId()).singleResult();
        taskService.complete(task.getId());

        // 老师审批
        List<Task> teacherTaskList = taskService.createTaskQuery().taskCandidateGroup("teacher").list();
        Map<String, Object> teacherMap = new HashMap<>();
        teacherMap.put("outcome", "通过");
        for (Task teacherTask : teacherTaskList) {
            taskService.complete(teacherTask.getId(), teacherMap);
        }

        // 校长审批
        List<Task> principalTaskList = taskService.createTaskQuery().taskCandidateGroup("principal").list();
        Map<String, Object> principalMap = new HashMap<>();
        principalMap.put("outcome", "通过");
        for (Task principalTask : principalTaskList) {
            taskService.complete(principalTask.getId(), principalMap);
        }

        // 查看历史
        List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(studentLeave.getId())
                .finished()
                .orderByHistoricActivityInstanceEndTime().asc()
                .list();
        for (HistoricActivityInstance activity : activities) {
            System.out.println(activity.getActivityName());
        }

    }

}

打印结果:

开始
流程开始
请假申请
申请流程
老师审批
通过
判断是否大于2天
小于2天
结束

将请假日期day改为5,打印结果:

开始
流程开始
请假申请
申请流程
老师审批
通过
判断是否大于2天
大于2天
校长审批
通过
结束

附录

数据表说明

Flowable的所有数据库表都以ACT_开头。第二部分是说明表用途的两字符标示符。服务API的命名也大略符合这个规则。

  • ACT_RE_* :’ RE ’表示repository(存储)。RepositoryService接口操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
  • ACT_RU_* :’ RU ’表示runtime。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。flowable只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。
  • ACT_ID_* : ’ ID ’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。
  • ACT_HI_* : ’ HI ’表示history。就是这些表包含着历史的相关数据,如结束的流程实例,变量,任务,等等。
  • ACT_GE_* : 普通数据,各种情况都使用的数据。
表分类表名表说明
一般数据ACT_GE_BYTEARRAY通用的流程定义和流程资源
 ACT_GE_PROPERTY系统相关属性
流程历史记录ACT_HI_ACTINST历史的流程实例
 ACT_HI_ATTACHMENT历史的流程附件
 ACT_HI_COMMENT历史的说明性信息
 ACT_HI_DETAIL历史的流程运行中的细节信息
 ACT_HI_IDENTITYLINK历史的流程运行过程中用户关系
 ACT_HI_PROCINST历史的流程实例
 ACT_HI_TASKINST历史的任务实例
 ACT_HI_VARINST历史的流程运行中的变量信息
用户用户组表ACT_ID_BYTEARRAY二进制数据表
 ACT_ID_GROUP用户组信息表
 ACT_ID_INFO用户信息详情表
 ACT_ID_MEMBERSHIP人与组关系表
 ACT_ID_PRIV权限表
 ACT_ID_PRIV_MAPPING用户或组权限关系表
 ACT_ID_PROPERTY属性表
 ACT_ID_TOKEN系统登录日志表
 ACT_ID_USER用户表
流程定义表ACT_RE_DEPLOYMENT部署单元信息
 ACT_RE_MODEL模型信息
 ACT_RE_PROCDEF已部署的流程定义
运行实例表ACT_RU_DEADLETTER_JOB正在运行的任务表
 ACT_RU_EVENT_SUBSCR运行时事件
 ACT_RU_EXECUTION运行时流程执行实例
 ACT_RU_HISTORY_JOB历史作业表
 ACT_RU_IDENTITYLINK运行时用户关系信息
 ACT_RU_JOB运行时作业表
 ACT_RU_SUSPENDED_JOB暂停作业表
 ACT_RU_TASK运行时任务表
 ACT_RU_TIMER_JOB定时作业表
 ACT_RU_VARIABLE运行时变量表
其他表ACT_EVT_LOG事件日志表
 ACT_PROCDEF_INFO流程定义信息

工作流引擎使用场景

工作流在企业管理系统中是高频使用的功能,一个最常见的例子是请假加班申请与审批的过程。事实上,工作流引擎能支持的业务场景远远不止单据审批,几乎所有涉及到业务流转、多人按流程完成工作的场景背后都可以通过工作流引擎作为支撑。基于工作流引擎,可以搭建客户关系管理系统(CRM)、运输管理系统(TMS)、仓储管理系统(WMS)、财务费用系统等多种复杂业务系统。对于达到一定规模的企业,良好的 BPM(业务流程管理,Business Process Management)体系可以支持创建公司内横跨不同部门的复杂业务流程,既提高工作效率、又可推动企业规范化发展。

image

Flowable 的四大引擎

Flowable BPMN 业务流程引擎

流程引擎是支持配置业务流转过程的关键模块。Flowable 支持 BPMN 2.0 行业标准,同时提供了一些 Flowable 自定义的 BPMN 扩展(extensions)可选用,允许通过导入 XML 文件或通过前端可视化界面建立流程。Flowable 本身提供了一个流程绘制的 UI 界面(Flowable Modeler 应用),如下图所示:

image

Flowable 业务流程引擎支持如下类型的流程元素:

1. 事件:事件(event)通常用于为流程生命周期中发生的事情建模。在 BPMN 2.0中,有两种主要的事件分类:捕获(catching)与抛出(throwing)事件。捕获事件为当流程执行到达这个事件时,会等待直到触发器动作。抛出事件当流程执行到达这个事件时,会触发一个触发器。具体事件包括定时器事件、启动事件、结束事件、消息事件、信号事件、边界事件等丰富类型。

2. 顺序流:顺序流(sequence flow)是流程中两个元素间的连接器。在流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。这意味着BPMN 2.0的默认是并行执行的:两个出口顺序流就会创建两个独立的、并行的执行路径。

顺序流上定义条件(conditional sequence flow)时为条件顺序流。当离开 BPMN 2.0活动时,默认行为是计算其每个出口顺序流上的条件。当条件计算为true时,选择该出口顺序流。如果该方法选择了多条顺序流,则会生成多个执行,流程会以并行方式继续。但这种情况并不适用于网关(gateway),不同类型的网关,会用不同的方式处理带有条件的顺序流。所有的BPMN 2.0任务与网关都可以使用默认顺序流(default sequence flow)。只有当没有其他顺序流可以选择时,才会选择默认顺序流作为活动的出口顺序流。流程会忽略默认顺序流上的条件。

3. 网关:网关(gateway)用于控制执行的流向,可类比路口的分叉来理解。如按BPMN 2.0 的用词也即是执行的「标志(token)」。网关可以消费(consuming)与生成(generating)标志。网关可细分为下列类型:


  • 排他网关(exclusive gateway):也叫异或网关 (XOR gateway),或者基于数据的排他网关 (exclusive data-based gateway),用于对流程中的决策建模。当执行到达这个网关时,会按照所有出口顺序流定义的顺序对它们进行计算。选择第一个条件计算为 true 的顺序流(当没有设置条件时,认为顺序流为true)继续流程。使用排他网关时,只会选择一条顺序流。当多条顺序流的条件都计算为true时,会且仅会选择在XML中最先定义的顺序流继续流程。



  • 并行网关:并行网关不计算条件,如果连接到并行网关的顺序流上定义了条件,会直接忽略该条件。并行网关(parallel gateway)可以将执行分支(fork)为多条路径,也可以合并(join)多条入口路径的执行,并行网关的功能取决于其入口与出口顺序流。如果并行网关同时具有多条入口与出口顺序流,可以同时具有分支与合并的行为。在这种情况下,网关首先合并所有入口顺序流,然后分裂为多条并行执行路径。



  • 包容网关:可看做排他网关与并行网关的组合。与排他网关一样,可以在包容网关的出口顺序流上定义条件,包容网关会计算条件。然而主要的区别是,包容网关与并行网关一样,可以同时选择多于一条出口顺序流。包容网关的汇聚行为比并行网关更复杂。



  • 基于事件的网关:基于事件的网关(event-based gateway)提供了根据事件做选择的方式。网关的每一条出口顺序流都需要连接至一个捕获中间事件。一个基于事件的网关,必须有两条或更多的出口顺序流。


4. 任务:Flowable 支持的任务类型超过十五种。


  • 用户任务:用于对需要人工执行的任务进行建模。当流程执行到达用户任务时,会为指派至该任务的用户或组的任务列表创建一个新任务。用户任务允许标识到期日期以及直接指派给用户。



  • 邮件任务:Flowable 引擎可以向一个或多个收信人发送邮件,支持 cc、bcc、HTML 文本等等,使用支持 SMTP 的外部邮件服务器发送邮件。



  • 业务规则任务:业务规则任务(business rule task)用于同步地执行一条或多条规则。在 V6.3.0 到 V6.4.1 版本中,Flowable 使用名为 Drools Expert 的 Drools 规则引擎执行业务规则。截至 V6.4.1 版本,业务规则中包含的 .drl 文件,必须与定义了业务规则服务并执行规则的流程定义一起部署。这意味着流程中使用的所有 .drl 文件都需要打包在流程 BAR 文件中,与任务表单等类似。由于 Flowable 自己的规则引擎 DMN 功能逐渐完善,对业务规则任务的支持可能会在后续版本中变动,具体要看 Flowable 官方更新文档。



  • 其他的任务类型还有脚本任务、Web 服务任务、Shell 任务、Java 服务任务、执行监听器、任务监听器等。


5. 子流程与调用活动:子流程(sub-process)是包含其他的活动、网关、事件等的活动。其本身构成一个流程,并作为更大流程的一部分。子流程完全在父流程中定义(所以也称作嵌入式子流程)。在复杂流程流转的场景下中子流程较为多见,使用这一特性可以比较灵活地维护包含子流程的审批路径。

调用活动(call activity)有别于一般的子流程,调用活动引用一个流程定义外部的流程,而子流程嵌入在原有流程定义内。调用活动的主要使用场景是,在多个不同流程定义中调用一个可复用的流程定义。

image

Flowable支持两种方式使用表单:使用(由Flowable提供的表单设计器创建的)表单定义的内置表单渲染,以及外部表单渲染。内置表单设计器的详细内容可以查看相应的表单引擎(Form Engine)用户手册。

Flowable 以事务的方式执行流程,可按照需求进行配置。如果 Flowable 被触发(启动流程,完成任务,为执行发送信号),Flowable 将沿流程执行,直到到达每个执行路径的等待状态。更具体地说,它以深度优先方式搜索流程图,并在每个执行分支都到达等待状态时返回。等待状态是「之后」再执行的任务,也就是说着 Flowable 将当前执行持久化,并等待再次触发。触发可以来自外部来源如用户任务或消息接受任务,也可以来自 Flowable 自身如定时器事件。

Flowable自带身份管理模块,但是从 Flowable V6 起身份管理(IDM IDentity Management)组件从 Flowable 引擎模块中抽出,并将其逻辑移至几个不同的模块。默认情况下,IDM引擎在Flowable引擎启动时初始化并启动。Flowable 提供的几个 web 应用中就包括 Flowable IDM(身份管理应用),为所有Flowable UI应用提供单点登录认证功能,并且为拥有 IDM 管理员权限的用户提供了管理用户、组与权限的功能。其他 Web 应用还有:


  • Flowable Modeler: 让具有建模权限的用户可以创建流程模型、表单、选择表与应用定义。



  • Flowable Task: 运行时任务应用。提供了启动流程实例、编辑任务表单、完成任务,以及查询流程实例与任务的功能。



  • Flowable Admin: 管理应用。让具有管理员权限的用户可以查询BPMN、DMN、Form及Content引擎,并提供了许多选项用于修改流程实例、任务、作业等。管理应用通过REST API连接至引擎,并与Flowable Task应用及Flowable REST应用一同部署。


所有其他的应用都需要 Flowable IDM 提供认证。每个应用的WAR文件可以部署在相同的servlet容器(如Apache Tomcat)中,也可以部署在不同的容器中。由于每个应用使用相同的cookie进行认证,因此应用需要运行在相同的域名下。

Flowable DMN 决策引擎

作为以 BPMN 为核心的工作流引擎,Flowable 原本与规则引擎的关联并不强,但实际业务流程中,有时需要由多个决策来决定流程走向,而每个决策都要根据自身的规则来决定,每个决策之间也可能存在关联。此时就需要规则引擎来提供决策支撑。在规则引擎开源产品中,Drools 是最知名的一款,它实现了PMML(Predictive Model Markup Language)规范,同时支持 DMN (Decision Model and Notation)标准。Flowable 目前实现了 DMN V1.1 规范的框架,由于 DMN 规范中要求对 PMML 提供兼容性,这意味着 Flowable 具有相对强大的业务规则的处理能力。

在 Flowable Modeler 应用中 DMN 引擎体现为「决策表」菜单,可以通过界面进行 Input 与 Output 的配置,可导入 .dmn 扩展名格式的 DMN 定义。在 OMG (Object Management Group)制定的 DMN 规范中也有相应的XML格式约束。如果 DMN 引擎已经插入流程引擎,就可以与其他流程相关资源一起,将 DMN 定义打包进业务存档(BAR)文件中。流程引擎部署服务会将 DMN 资源部署至 DMN 引擎。

image

DMN 定义由决策(decision)和其他东西组成,决策由表达式描述。DMN 标准描述了几种表达式的类型,目前在 Flowable DMN 中仅支持决策表(decision table)类型的表达式。决策表分为输入表达式与输出表达式两个主要区域。在输入表达式中,可以定义变量,用于规则输入项(input entries)的表达式。可以通过选择Add Input(添加输入),定义多个输入表达式。在输出表达式中,可以定义选择表执行结果要创建的变量(变量的值将用于输出项表达式,在下面解释)。可以通过选择Add Output(添加输出),定义多个输出表达式。

在决策表编辑界面,可以选择命中策略,共有两大类(单命中、多命中)七种命中策略可选:

(1)单命中、第一命中(single hit & FIRST):多个规则允许交叉,执行从上到下的第一条命中项。

(2)单命中、唯一命中(single hit & UNIQUE):多个规则不允许交叉,执行从上到下的第一条唯一命中项。

(3)单命中、任一命中(single hit & ANY):规则允许交叉,但是所有输出的优先级相同,随机执行一条命中项。

(4)单命中、优先级(single hit & PRIORITY):多个命中规则的优先级不同,执行优先级最高的那条。

(5)多命中、输出优先级排序(multiple hit & OUTPUT ORDER):按照输出优先级递减的顺序返回所有命中。

(6)多命中、规则顺序排序(multiple hit & RULE ORDER):按照规则顺序返回所有命中。

(7)多命中、聚合(multiple hit & COLLECT):按照随机顺序返回所有命中。

DMN 可以被 BPMN 定义的流程调用:在流程中引入一个决策任务(Decision task),并选中引用决策表(Decision table reference),来使用新创建的选择表。想深入了解DMN特性可参考这篇案例说明:https://flowable.com/blog/2016/09/decision-model-and-notation-dmn-how-to-start-a-project-2/

image

Flowable CMMN 案例模型引擎

CMMN 是 Case Management Model 的缩写,在 Flowable Modeler 应用中体现为「案例模型」菜单,使用时可以类似于流程引擎可视化配置流程,也可通过XML格式文件。CMMN(Case Management Model and Notation)行业标准 V1.1 版本于2016年发布,目前 Flowable 的 V6.4.1 已支持此标准。

与 BPMN 引擎相比,CMMN 引擎适用于如下几种场景:

(1)重复与并行的工作分发。BPMN 引擎在处理顺序执行、职责分工明确的工作流程时有优势,但面对动态、自由、并行的情况时,BPMN 显得灵活性不足,此时CMMN 则更适合应对。

(2)处理带有生命周期特征的场景,如客户、产品、项目、雇员。以项目为例,项目的立项、中止、收尾、交付等阶段(phases),可以在 CMMN 中通过阶段(Stages)概念在更高层次进行描述。

image

CMMN 中一个案例模型呈现为一个公文夹的样式。每个案例模型都包含一个用于安置计划元素的「计划模型」,每个计划元素包含一个明确其类型和可能配置选项的计划元素定义,常见计划元素如用户任务(human task)、里程碑(milestone)、流程任务(process task)、案例任务(case task)和阶段(stage)。例如下图中的计划模型包含三个用户任务计划项和一个里程碑。

image

Flowable CMMN 引擎支持如下类型的案例元素:

1. 阶段(Stage):阶段用于把一组元素聚合在一起,可以有进入和退出的条件。阶段可以嵌套,一个阶段中的计划元素只有其父阶段激活时才生效。

2. 任务(Task):任务是发生于引擎外部的事件,包含名称、阻塞(决定任务是否阻塞的布尔值)、阻塞表达式(表达式的布尔值决定任务是否阻塞)等属性。

3. 用户任务(Human task):通常指需要用户通过表单执行的手动任务,包含一系列属性。

4. 里程碑(Milestone):里程碑标识某一具体案例到达特定点。

5. 案例任务(Case task):案例可以嵌套,案例中的子案例就是案例任务。

6. 流程任务(Process task):当流程任务阻塞时,实例化的计划要素会处于激活状态,直至流程任务完成。

7. 条件(Criteria):分为进入条件和退出条件。

8. 决策任务(Decision task):调用 DMN 引擎中的决策表。

9. HTTP任务、脚本任务、Java 服务任务、时间监听器等:与 BPMN 中的相应元素含义相近,不再赘述。

Flowable Form 表单引擎

Flowable 框架中将表单作为一个独立的子模块,可以将表单作为一个服务在其他模块中进行调用,表单服务就可以控制所有流程所使用的表单以及表单字段的可读、可写等操作。表单相关的使用可分为表单的定义以及表单的运行实例两个阶段。表单定义支持导入以 .form 为后缀的表单定义文件(JSON 语言编写) 。在 Flowable Modeler 应用中,「表单」菜单下可以进行简单的表单拖拽拼接可视化配置定义。flowable.com网站上也提供了一个可视化构建表单案例可以参考https://flowable.com/flowable-forms/

© 版权声明
THE END
喜欢就支持一下吧
点赞1赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容