Flowable实战(四)BPMN2.0 启动与结束事件

1,007 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、BPMN2.0

  BPMN2.0规范是一个标准,开源框架和不同供应商都遵循这份标准,使得最终用户不会因为依赖专有解决方案,而被供应商“绑架”。有了BPMN2.0标准,不同解决方案之间的迁移,变得十分简单平滑。

  缺点则是标准通常是不同观点大量讨论与妥协的结果,有些结构或方法会十分笨重。Flowable在实现规范的基础上进行了功能和使用性扩展。

  • 自定义扩展是在标准方式的基础上进行简化。因此当你决定使用自定义扩展时,仍然可以用标准方式。
  • 使用自定义扩展时,总是通过flowable: 命名空间前缀,明确标识出XML元素、属性等。
  • Flowable引擎也支持activiti: 命名空间前缀。

  注:在官方文档中,启动和结束事件已有较详细的介绍,是英文版。启动和结束事件是流程里重要的内容,现在做个汇总整理。

二、启动事件

启动事件(start event)是流程的起点。

  • 启动事件在XML中,类型由子元素声明来定义。
  • 启动事件保持等候状态,直到特定的触发器被触发。
  • 启动事件是细线图形。

2.1 空启动事件

2.1.1 描述

  空启动事件(none Start Event),指的是未指定触发器,由用户调用的启动事件。

2.1.2 图示

  空启动事件用空心圆圈表示,中间没有图标(也就是说,没有触发器)。

空启动.png

2.1.3 XML表示

  空启动事件的XML表示格式,就是普通的启动事件声明,而没有任何子元素(其他种类的启动事件都有用于声明其类型的子元素)。

    <startEvent id="start" name="my start event" />

2.1.4 使用方法:

    ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();

2.1.5 自定义扩展

  formKey: 引用表单定义,用户需要在启动时填写的表单。(目前只需了解到启动事件可以绑定表单即可,详细内容在表单章节中讲解。)

    <startEvent id="request" flowable:formKey="simpleForm" />

2.2 定时器启动事件

2.2.1 描述

  定时器启动事件(timer start event)在指定时间内创建一次或多次的流程实例。

  • 定时器启动事件,在流程部署的同时就开始计时。不需要调用startProcessInstanceByXXX就会在时间启动。调用startProcessInstanceByXXX时会在定时启动之外额外启动一个流程。
  • 当部署带有定时器启动事件的流程的更新版本时,上一版本的定时器作业会被移除。这是因为通常并不希望旧版本的流程仍然自动启动新的流程实例。

2.2.2 图示

  定时器启动事件,用其中有一个钟表图标的圆圈来表示。

定时器.png

2.2.3 XML表示

  定时器启动事件的XML表示格式,是普通的启动事件声明加上定时器定义子元素。

定时器定义必须且只能包含下列的一种元素:

  • timeDate。这个元素指定了ISO 8601格式的固定时间。在这个时间就会触发触发器。例如:
    <timerEventDefinition>
        <timeDate>2022-01-11T12:13:14</timeDate>
    </timerEventDefinition>
  • timeDuration。要定义定时器需要等待多长时间再触发,同样使用ISO 8601格式(BPMN 2.0规范要求)。例如(等待10天):
    <timerEventDefinition>
        <timeDuration>P10D</timeDuration>
    </timerEventDefinition>
  • timeCycle。指定重复周期,可用于周期性启动流程。例如(重复三次启动,每次间隔为10小时,到指定时间时结束重复):

        <timerEventDefinition>
            <timeCycle>R3/PT10H/2022-01-12T23:59:59+00:00</timeCycle>
        </timerEventDefinition>
    

    也可以使用变量,如 ${EndDate}

        <timerEventDefinition>
            <timeCycle>R3/PT10H/${EndDate}</timeCycle>
        </timerEventDefinition>
    

2.3 消息启动事件

2.3.1 描述

  消息启动事件(message start event)使用具名消息启动流程实例。消息名用于定位指定的启动事件。

  当部署具有一个或多个消息启动事件的流程定义时,会做如下判断:

  • 一个流程定义不得包含多个同名的消息启动事件。
  • 在流程定义中,一个或多个消息启动事件引用了已经部署的另一流程定义中消息启动事件的消息名,则会抛出异常。
  • 流程版本:在部署流程定义的新版本时,会取消上一版本的消息订阅,即使新版本中并没有这个消息事件。

2.3.2 图示

  消息启动事件用其中有一个消息事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。

消息启动.png

2.3.3 XML表示

  消息启动事件的XML表示格式,为普通启动事件声明加上messageEventDefinition子元素:

    <definitions id="definitions"
                 xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
                 xmlns:flowable="http://flowable.org/bpmn"
                 targetNamespace="Examples"
                 xmlns:tns="Examples">
​
        <message id="newInvoice" name="newInvoiceMessage" />
​
        <process id="invoiceProcess">
​
            <startEvent id="messageStart" >
                <messageEventDefinition messageRef="tns:newInvoice" />
            </startEvent>
            ...
        </process>
​
    </definitions>

2.3.4 使用方法

  在启动流程实例时,可以使用下列RuntimeService中的方法,触发消息启动事件:

    ProcessInstance startProcessInstanceByMessage(String messageName);
    ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
    ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey,
        Map<String, Object< processVariables);

  messageName是由message元素的name属性给定的名字。messageEventDefinition的messageRef属性会引用message元素。

2.4 信号启动事件

2.4.1 描述

  信号启动事件(signal start event),使用具名信号启动流程实例。

2.4.2 图示

  信号启动事件用其中有一个信号事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。

信号启动.png

2.4.3 XML表示

  信号启动事件的XML表示格式,为普通启动事件声明,加上signalEventDefinition子元素:

<signal id="theSignal" name="The Signal" />
​
<process id="processWithSignalStart1">
  <startEvent id="theStart">
    <signalEventDefinition id="theSignalEventDefinition" signalRef="theSignal"  />
  </startEvent>
  <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
  <userTask id="theTask" name="Task in process A" />
  <sequenceFlow id="flow2" sourceRef="theTask" targetRef="theEnd" />
  <endEvent id="theEnd" />
</process>

2.4.4 使用方法

  信号可以由流程实例中的信号抛出中间事件(intermediary signal throw event),或者API(runtimeService.signalEventReceivedXXX方法)触发。

  两种方式都会启动所有拥有相同名字信号启动事件的流程定义。

  请注意可以选择异步还是同步启动流程实例。

  需要为API传递的signalName,是由signal元素的name属性决定的名字。signal元素由signalEventDefinition的signalRef属性引用。

注意:消息与信号的区别:消息是一对一的,一个消息只能启动一个流程事件。信号是全局的,广播式的,一个信号可以启动多个流程事件。

2.5 异常启动事件

2.5.1 描述

  异常启动事件(error start event),可用于触发事件子流程(Event Sub-Process)。异常启动事件不能用于启动流程实例

2.5.2 图示

  异常启动事件用其中有一个异常事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。

异常启动.png

2.5.3 XML表示

  异常启动事件的XML表示格式,为普通启动事件声明加上errorEventDefinition子元素:

    <startEvent id="messageStart" >
            <errorEventDefinition errorRef="someError" />
    </startEvent>

三、结束事件

  结束事件(end event)标志着流程或子流程中一个分支的结束。结束事件总是抛出(型)事件。这意味着当流程执行到达结束事件时,会抛出一个结果。结果的类型由事件内部的黑色图标表示。在XML表示中,类型由子元素声明给出。

3.1 空结束事件

3.1.1 描述

  空结束事件(none end event),意味着当到达这个事件时,没有特别指定抛出的结果。因此,引擎除了结束当前执行分支之外,不会多做任何事情。

3.1.2 图示

  空结束事件,用其中没有图标(没有结果类型)的粗圆圈表示。

空结束.png

3.1.3 XML表示

  空事件的XML表示格式为普通结束事件声明,没有任何子元素(其它种类的结束事件都有子元素,用于声明其类型)。

    <endEvent id="end" name="my end event" />

3.2 异常结束事件

3.2.1 描述

  当流程执行到达异常结束事件(error end event) 时,结束执行的当前分支,并抛出错误。

3.2.2 图示

  异常结束事件事件用内部有一个异常图标的标准结束事件(粗圆圈)表示。异常图标是全黑的,代表抛出的含义。

异常结束.png

3.2.3 XML表示

  异常结束事件表示为结束事件,加上errorEventDefinition子元素:

    <endEvent id="myErrorEndEvent">
      <errorEventDefinition errorRef="myError" />
    </endEvent>

  errorRef属性可以引用在流程外定义的error元素:

    <error id="myError" errorCode="123" />
    ...
    <process id="myProcess">
    ...

  errorerrorCode用于查找匹配的异常捕获边界事件。如果errorRef不匹配任何已定义的error,则该errorRef会用做errorCode的快捷方式。这个快捷方式是Flowable特有的。下面的代码片段在功能上是相同的。

    <error id="myError" errorCode="error123" />
    ...
    <process id="myProcess">
    ...
      <endEvent id="myErrorEndEvent">
        <errorEventDefinition errorRef="myError" />
      </endEvent>
    ...

  与下面的代码功能相同

    <endEvent id="myErrorEndEvent">
      <errorEventDefinition errorRef="error123" />
    </endEvent>

  请注意errorRef必须遵从BPMN 2.0规范。

3.3 终止结束事件

3.3.1 描述

  当到达终止结束事件(terminate end event) 时,当前的流程实例或子流程会被终止。也就是说,当执行到达终止结束事件时,会判断第一个范围 scope(流程或子流程)并终止它。请注意在BPMN 2.0中,子流程可以是嵌入式子流程,调用活动,事件子流程,或事务子流程。有一条通用规则:当存在多实例的调用过程或嵌入式子流程时,只会终止一个实例,其他的实例与流程实例不会受影响。

  可以添加一个可选属性terminateAll。当其为true时,无论该终止结束事件在流程定义中的位置,也无论它是否在子流程(甚至是嵌套子流程)中,都会终止(根)流程实例。

3.3.2 图示

  终止结束事件用内部有一个全黑圆的标准结束事件(粗圆圈)表示。

终止结束.png

3.3.4 XML表示

  终止结束事件,表示为结束事件,加上terminateEventDefinition子元素。

  请注意terminateAll属性是可选的(默认为false)。

    <endEvent id="myEndEvent >
      <terminateEventDefinition flowable:terminateAll="true"></terminateEventDefinition>
    </endEvent>

3.4 取消结束事件

3.4.1 描述

  取消结束事件(cancel end event)只能与BPMN事务子流程(BPMN transaction subprocess)一起使用。当到达取消结束事件时,会抛出取消事件,且必须由取消边界事件(cancel boundary event)捕获。取消边界事件将取消事务,并触发补偿(compensation)。

3.4.2 图示

  取消结束事件用内部有一个取消图标的标准结束事件(粗圆圈)表示。取消图标是全黑的,代表抛出的含义。

取消结束.png

3.4.3 XML表示

  取消结束事件,表示为结束事件,加上cancelEventDefinition子元素。

    <endEvent id="myCancelEndEvent">
      <cancelEventDefinition />
    </endEvent>

四、小结

  理论是实践的基础,本篇汇总BPMN2.0 规范和Flowable扩展下的启动和结束事件,为后面的实战做准备。