事件

概览

在 BPMN 表示法中,事件表示在业务流程中发生的事情。 事件可以发起流程中活动的启动、继续或完成等动作。

事件还可用于对各种场景进行建模,例如接收消息、时间流逝或发生错误。 通过在 BPMN 图中引入事件,用户可以有效地捕获业务流程的行为和流向。

“事件” 这个词有两种不同的含义:

  1. 流程中发生某些事情时

  2. BPMN 图的一个元素

事件可以在不显示在流程图上的情况下发生。例如,消息事件应以编程方式引发。

事件分类

首先,事件因它们在过程中的位置而异,可能是启动、中间或结束。 因此可以分为 startintermediateend 事件。

事件的行为由激活事件的触发器定义。 例如,消息或定时器。

流程可以使用或产生事件。 因此,这些 BPMN 事件称为 'catching' 和 'throwing' 事件。

某些事件还可以添加到活动;此类事件称为 'boundary'。

以及,事件可能具有中断或继续流程的属性。 这里,事件可分为 interruptiblenon-interruptible 事件。

为方便起见,下面的表格中总结了事件的分类:

标准 分类

流程中的位置

Start, Intermediate, End,

可触发

None, Timer, Message, Signal, Error, Compensation

角色

Catching/Throwing

是否附加活动

Boundary

是否能中断流程

Interrupting 或 Non-interrupting

流程中的位置

根据事件在流程中的位置,可分为:

所有事件在图中都显示为一个圆圈,圆圈线的类型(单线、双线、粗线) 表示事件在流程中的不同位置(启动、中间、结束)。

start end process

下面 XML 中是上图事件的一个示例:

  <bpmn:process id="Process_1" isExecutable="true">
    <bpmn:startEvent id="start-event" name="Start event"> (1)
      <bpmn:outgoing>Flow_out_start</bpmn:outgoing>
    </bpmn:startEvent>
    . . .
    <bpmn:intermediateThrowEvent id="intermediate-event" name="Intermediate event"> (2)
      <bpmn:incoming>Flow_in</bpmn:incoming>
      <bpmn:outgoing>Flow_out</bpmn:outgoing>
    </bpmn:intermediateThrowEvent>
    . . .
    <bpmn:endEvent id="end-event" name="End event"> (3)
      <bpmn:incoming>Flow_in_end</bpmn:incoming>
    </bpmn:endEvent>

  </bpmn:process>
1  — 启动事件
2  — 中间事件
3  — 结束事件

事件触发器

在 BPMN 流程中,通过事件触发器指定某个事件应当在何时发生。 BPMN 中常用的几种事件触发器包括:

触发器可以手动或通过 API 调用激活。

捕获或抛出事件

在 BPMN 2.0 中,存在两个主要事件类别:catchingthrowing 事件。

  • 捕获(Catching): 当流程执行至该事件时,将等待触发器的激活。 触发器的类型由 XML 中的内部图标或类型声明定义。 捕获事件与抛出事件在图形上通过未填充的内部图标(通常为白色)进行区分。

  • 抛出(Throwing): 当流程执行至该事件时,将激活触发器。 触发器的类型由 XML 中的内部图标或类型声明定义。 抛出事件与捕获事件在图形上通过填充的内部图标(通常为黑色)进行区分。

示例,请参考下面的捕获和抛出信号事件:

sigtal catching throwing

边界事件

边界事件是捕获(型)事件,依附于活动(任务、嵌入的子流程或调用活动)。 可以是附着在活动上的多个事件。 边界事件总是捕获事件,无法被抛出。

事件子流程 不能有边界事件。

在 XML 中,边界事件由特殊标签标记,具有 attachedToRef 属性,执行依附的活动:

    <boundaryEvent id="Event_0gl2f4v" attachedToRef="Activity_1fsayqc">
      <timerEventDefinition id="TimerEventDefinition_0w9bip4" />
    </boundaryEvent>

示例

边界事件可以依附于任务、嵌入的子流程或调用活动。

boundary events example

活动处于运行状态时,事件会监听为其设计的触发器。 当触发器触发时,根据事件类型的不同(中断或非中断型),其依附的活动可以被中断。

流程中断

该事件可以中断正常的流程执行。 适用于事件子流程中的边界事件和启动事件。

活动的边界事件
  • 中断(Interrupting) — 活动被中断,流程按照该事件的流向继续。

  • 非中断(Non-interrupting) — 与主流程同步开启一个新的流程分支,不会中断主流程的流向。

boundary events

中断事件在图中展示为一个常规的过程中事件,依附于活动(任务或子流程), 而非中断事件的边线为虚线。

非中断事件可以触发多次,每次都会开启一个新的流程执行(生成新令牌),直到任务完成。 例如,非中断循环计时器每 5 分钟触发一次,并向用户发送通知。

行为类型由 cancelActivity 属性定义。 默认设置为 true,对于中断事件,可以省略该属性的配置。 对于非中断事件,需要显式设置为 false

示例,非中断定时器事件:

    <boundaryEvent id="Event_01" cancelActivity="false" (1)
        attachedToRef="user-task">
      <timerEventDefinition id="TimerEventDefinition_14a8e0l" />
    </boundaryEvent>
1  — 定义非中断定事件。

事件定义

在 BPMN 中,消息(messages)信号(signals) 是一种流程内或流程间不同元素通信的机制。 消息和信号在 BPMN 图中定义各种元素之间的交互和依赖关系方面都起着至关重要的作用。 错误(Errors) 与消息和信号类似,也可以用于控制流程的流向。

消息和信号在事件中使用之前必须先进行定义。 在某些情况下,可以省略错误定义。

如需在 Studio 中定义事件,打开流程模型后,不要选择任何内容,此时可以访问流程的属性, 找到信号和消息定义的部分:

event definition

协作 的情形中, 请选择需要修改的参与者(泳池)。

定义一个消息

创建消息时,需要定义其 idname

define messages
定义一个信号

创建信号时,需要定义其 idname; 必须选择一个 scope(范围)参数,Global(全局)Process instance(仅流程实例)

define signal
定义一个错误

创建错误时,需要定义其 idname;此外,还可以设置 Error code(错误码)

errors definition
XML 表示

消息、信号和错误在 XML 中通常位于 <process><diagram> 之间。

</process>
<message id="green" name="Green" /> (1)
<message id="yellow" name="Yellow" />
<message id="red" name="Red" />
<signal id="ready" name="Ready" flowable:scope="global" /> (2)
<signal id="stop" name="Stop" flowable:scope="processInstance" />
<error id="failure" name="Failure" errorCode="500" />  (3)
<error id="fatal" name="Fatal" />  <bpmndi:BPMNDiagram id="BPMNDiagram_process">
1  — 消息定义
2  — 信号定义
3  — 错误定义

如果需要在不同的流程中使用同样的消息和信号, 必须在每个 BPMN 模型中都进行定义。 you must create their definitions in each BPMN model.

事件子流程的启动事件

事件子流程可以有中断或非中断启动事件。

  • 中断 — 当事件子流程结束时,主流程也终止。

  • 非中断 — 事件子流程并行执行并结束, 主流程继续。

interrupting non events subprocess

在上图中,第一个子流程在时间结束时中断主流程。 第二个子流程执行服务任务并结束,而不会影响主流程。

事件订阅

事件订阅是一种机制,流程可以在继续执行特定事件之前等待特定事件的发生。 事件订阅类型包括:

  • 消息(Message)

  • 信号(Signal)

  • 定时器(Timer)

  • 错误(Error)

  • 补偿(Compensation)

创建

有两种情况:

  • 启动事件 —  订阅在部署时创建。

  • 中间和边界事件 — 在流程进行到该事件时创建订阅。

每个事件订阅都可以配置一些参数,这些参数用来定义事件如何与流程实例相关联。 包括指定事件的类型、名称以及任何触发该订阅的其他必要的关联参数。

保存

事件订阅存储在数据库的 ACT_RU_EVENT_SUBSCR 表中。 其中包含有关事件类型、流程实例 ID 以及消息事件所需的其他关联参数的信息。

触发

当相应的事件发生时(例如,收到一条消息或定时器到期), 流程引擎会检查与事件条件匹配的订阅信息。 对于消息事件,应用程序必须使用关联参数将消息与正确的流程实例相关联。


  1. 创建事件订阅

    可以通过编程的方式为消息、信号和定时器事件创建事件订阅。例如,可以通过发送消息来启动流程实例:

    // 用消息启动流程
    ProcessInstance processInstance = runtimeService.startProcessInstanceByMessage("orderPlaced", processVariables);
  2. 查询事件订阅

    可以查询已有的事件订阅,以查看哪些流程正在等待特定的事件。例如:

    List<EventSubscription> messageSubscriptions = runtimeService.createEventSubscriptionQuery()
        .eventType("message")
        .list();
  3. 获取事件订阅

    通过 RuntimeService 可以获取订阅的列表。 例如,获取信号订阅:

    // 查询所有的信号事件订阅
    List<EventSubscription> signalSubscriptions = runtimeService.createEventSubscriptionQuery()
        .eventType("signal")
        .list();

    如需获取其他类型的事件,可以用 "message""error""compensate" 参数值。

    对于定时器,需要使用 ManagementService

    List<Job> timerJobs = managementService.createTimerJobQuery().list();
  4. 触发事件订阅

    可以在相应事件发生时以编程方式触发事件订阅。 例如,要触发消息事件:

    runtimeService.messageEventReceived("orderPlaced", executionId, processVariables);
  5. 删除事件订阅

    如果不再需要事件订阅,可以将其删除。 例如,要删除特定事件订阅:

    runtimeService.createEventSubscriptionQuery()
        .eventType("message")
        .processInstanceId(processInstanceId)
        .singleResult();
通过监听器处理事件

参阅 监听器 部分。

启动事件

启动事件 是流程的入口点 当引擎尝试启动执行流程时,会在 BPMN 模型中搜索启动事件。

因此,一个流程 必须 具有一个 启动事件。 启动事件总是捕获(型):从概念上讲,该事件(在任何时候)都在等待,直到某个触发器发生。

启动事件可以是下列类型之一:

多个启动事件

尽管 BPMN 支持多个启动事件,但从技术上讲,流程可能只有一个 启动事件。否则,将导致部署错误。 不要使用多个 启动事件,如下图所示:

multiple start none

但是,流程可以使用多个其他类型的启动事件:

multiple start events good

可以使用多个消息(或信号)启动事件,前提是这些消息(或信号)不同。

结束事件

结束事件表示流程或子流程中路径的结束。结束事件始终为 抛出(型)Jmix BPM 中可以有以下结束事件:

多个结束事件

从形式上讲,结束事件不是强制性的。当没有要执行的活动时,流程就会结束。 但是,最好使用结束事件完成流程的每个路径。

end event not mandatory

不要尝试将所有流都引导至同一个结束事件,这样会让图表变得混乱。

end events examples

多个结束事件可以更好地分析流程如何结束。

multiple end events

空事件

空(None)事件是未指定的事件。

空启动事件

从技术上讲,空启动事件表示未指定用于启动该流程实例的触发器。 也就是说,引擎无法猜测该流程实例何时启动。

嵌入式子流程 具有空启动事件。
图形表示法

空启动事件通过没有内部图标(即,没有触发类型)的圆圈表示。

none start event
属性

空启动事件用两个特殊的属性:

  • 流程变量(Process variables) — 提供通过 API 启动流程的参数信息。

  • 表单(Form) — 定义手动启动流程时展示的 UI。

start event properties

可以通过单击 BPMN Inspector 面板中的 create 链接来定义启动事件中的流程变量:

create process variables in start event

输入变量名并按回车:

create variable window

默认情况下,新变量使用 String 类型创建,也可以将其类型更改为所需的类型。

edit process variable in start event

此处定义的流程变量不会在流程实例中创建。 必须以某种方式进行初始化。 例如,可以使用脚本任务。

如果在表单之前创建了流程变量,则会在表单中添加这些变量。

关于 表单 的配置,请参阅 流程表单 部分。

XML 表示

空启动事件的 XML 表示形式是一个常规的启动事件声明,但没有任何子元素。 (其他启动事件类型都有一个声明类型的子元素)。

<startEvent id="startEvent1" name="Start"> (1)
  <extensionElements>
    <jmix:processVariables>
      <jmix:processVariable name="invoiceId" type="string" /> (2)
    </jmix:processVariables>
    <jmix:formData type="no-form" /> (3)
  </extensionElements>
  <outgoing>Flow_0h77bcd</outgoing>
</startEvent>
1  — 启动事件的定义
2  — 流程变量
3  — 这里可以是一个表单的定义

API 触发空启动事件

当通过 API 调用名称类似 startProcessInstanceByXXX 的方法之一启动流程实例时,将使用空启动事件。

例如:

ProcessInstance processInstance = runtimeService
        .startProcessInstanceByKey("process-id");

Flowable API 使用术语 'process definition key' ,相当于 Jmix Studio 中的 'process id'。

请参阅 Flowable API 部分。

中间空事件

中间空事件(Intermediate none events) 可用于表示流程中达到的某些状态。 引擎本身在事件中不做任何事情,只是穿过该事件继续行进。

图形表示法

中间空事件在图中展示为双线且没有内部图标(即,没有触发器类型)的圆圈。

intermediate none event
属性

中间空事件无特定属性

XML 表示

中间空事件的 XML 是使用 intermediateThrowEvent 定义的事件声明,没有任何子元素。

  <intermediateThrowEvent id="IntermediateEvent" />

示例

中间空事件 可用于监控并理解流程的运行情况, 例如,作为里程碑或关键绩效指标(KPI)。

none intermediate event example

空结束事件

空结束事件(none end event) 是一种结束事件,表示流程完成,但没有任何特定输出或结果。 不会触发流程中的任何后续活动或流。

图形表示法

空结束事件在图中展示为粗线且没有内部图标的圆圈。

none end event
属性

空结束事件无特定属性

XML 表示
    <endEvent id="end-event" name="End">
      <incoming>Flow_0qwib28</incoming>
    </endEvent>

定时器事件

BPMN 中的定时器事件是根据预定义的时间点或持续时长触发的事件。 定时器事件可以指定某些活动何时执行,以控制流程的走向。

定时器事件有两种类型:

另外,定时器也可以用作 边界事件,可以是中断或非中断。

timer events example

定时器启动事件

定时器启动事件 用来在特定时间创建流程实例。 可用于仅启动一次或按特定时间间隔启动的流程。

嵌入式子流程 不能有定时器启动事件, 但是 事件子流程 可以有。

图形表示法

定时器启动事件在图中展示为内部有时钟图标的圆圈。

timer start event
属性

定时器启动事件有一个特殊的 Timer Definition 属性,用于定义其类型和表达式。 参阅 定时器类型

timer start event properties
XML 表示

定时器启动事件的 XML 是一个常规的启动事件声明,带有定义定时器的子元素。 有关配置的详细信息,请参阅定时器定义。

<startEvent id="theStart">
  <timerEventDefinition> (1)
        . . . (2)
  </timerEventDefinition>
</startEvent>
1  — 定时器事件定义
2  — 定义子元素

使用定时器启动事件

在此示例中,主流程由定时器事件启动。 它有两个事件子流程,也是由定时器启动。 第一个是非中断的,可以在流程启动后的某个时刻完成一些活动。 第二个事件子流程有一个可中断的定时器,当这个定时器事件触发时,主流程将停止。

timer start event example
不要在带定时器启动事件的流程中使用 initiator 变量,否则会导致执行错误。 除非通过编程方式定义和设置值。

定时器中间事件

定时器中间事件(Timer intermediate event) 可以作为秒表。执行到该事件时,将启动定时器。 当定时器在指定的时间间隔或指定的时间到达后触发时,流程将继续。

定时器中间事件是一个 等待状态

图形表示法

定时器中间事件在图中展示为中间捕获事件,内部有一个定时器图标。

timer untermediate catch event
属性

定时器中间事件的属性与定时器启动事件一样。

intermediate timer properties
XML 表示

定时器中间事件的 XML 定义是中间捕获事件。 此时,其表示类型的子元素是 timerEventDefinition

<intermediateCatchEvent id="timer">
  <timerEventDefinition>
    <timeDuration>PT8H</timeDuration> (1)
  </timerEventDefinition>
</intermediateCatchEvent>
1  — 定时器类型,例如 duration

定时器类型

系统支持以下三种定时器:

timer types
Duration

 — 在指定的时长之后触发。

Cycle

 — 根据 Cron 表达式 周期触发。

Date

 — 在指定的日期触发;如果指定的日期是以前的日期,则忽略该事件。

对于启动定时器事件,时长是从流程部署到服务器的那一刻就开始计算。

配置时间

设置定时器的时间参数有两种方式:

ISO 8601 标准

ISO 8601 是一项关于全球日期时间相关数据交换和通信的国际标准。

示例:
2035-06-17T07:42:14

 — 日期时间:2035 年 6 月 17 日,7 时 42 分 14 秒

2050:01:01

 — 日期时间:2050 年 1 月 1 日,0 时 0 分 0 秒

PT30D

 — 时长,30 天

PT10M

 — 时长,10 分

P3Y6M4DT12H30M5S

 — 时长,3 年 6 个月 4 天 12 小时 30 分钟 5 秒

R3PT10H

 — 周期,每 10 小时重复 3 次

不要使用小于 3 秒的短时长。BPM 不是一个实时系统。

参阅 ISO 8601 标准网站了解更多。

Cron 表达式

Cron 是在类 Unix 操作系统中使用的一种基于时间的作业调度系统。支持用户在特定时间、日期或间隔运行计划任务或命令。“cron” 一词来自 “chronos”,在希腊语中是时间的意思。

可以使用 cron 表达式指定时间周期;例如,下面的示例表示从整点开始,每 5 分钟触发一次:

0 0/5 * * * ?

定时器中间事件 中,Cron 表达式只能用于周期性的事件类型。 否则在部署流程时会出错。

消息事件

消息事件是引用 消息 的事件。 用于对业务流程的不同部分之间或不同流程之间的通信进行建模。 消息事件表示在流程流中发送(抛出)或接收(捕获)消息。

消息事件有两种类型:

另外,消息事件也可以作为边界事件使用。

message events types

Jmix BPM 不支持消息抛出事件(中间、结束)。 参阅 workaround

消息启动事件

消息启动事件(message start event) 可使用命名消息启动流程实例。

图形表示法

消息启动事件在图中显示为带有消息事件符号的圆圈。 如果符号未填充,则表示捕获 (接收) 行为。

message start event
属性

消息启动事件必须具有 Message 属性,指向已有的 消息定义。这是必须的,否则会导致部署错误。

start message properties
XML 表示

消息启动事件的 XML 表示是带有 messageEventDefinition 子元素的普通启动事件:

    <startEvent id="Message_start_event>
      <messageEventDefinition id="MessageEventDefinition_invoice"
            messageRef="new-invoice-message" /> (1)
    </startEvent>
1  — 指向消息定义。

使用消息启动事件

一个流程可以有一个或多个消息启动事件,但是必须是不同的消息。

流程部署后,引擎会为每个消息启动事件创建一条消息 订阅。 任何该流程老版本的订阅都将关闭。

消息启动事件的名称在所有已部署的流程定义中必须唯一。 如果一个流程定义包含一个或多个消息启动事件,事件中引用了已部署的其他流程定义使用的同名启动消息, 流程引擎在部署时会抛出异常。

编程式触发消息启动事件

启动流程实例时,消息启动事件可以通过 RuntimeServicestartProcessInstanceByMessage 方法触发。

在 API 调用时,需要使用消息的 name 作为参数,而非 id。例如,我们有如下消息定义:

<message id="green" name="Green" />

那么 API 方法可以这样调用:

runtimeService.startProcessInstanceByMessage("Green");

嵌入式子流程不支持消息启动事件。

消息中间捕获事件

消息中间捕获事件(intermediate catching message event) 使用特定的名称捕获消息。

图形表示法

中间捕获消息事件在图中展示为典型的中间事件(双线的圆圈),内部有消息图标。消息图标未填充表示“捕获”。

message catch event
属性

消息中间捕获事件与消息启动事件的属性相同。

catch message event properties
XML 表示

消息中间事件在 XML 中定义为中间捕获事件。 此时,其表示类型的子元素是 messageEventDefinition

<intermediateCatchEvent id="catch-message-event"
    name="Catch message">
  <messageEventDefinition id="MessageEventDefinition_16bx9rl"
    messageRef="message-one" />
</intermediateCatchEvent>

当流程进入中间消息捕获事件时,将创建相应的消息订阅。 流程实例会在这里停止并等待,直到收到消息。 之后,捕获事件完成,流程继续执行。

消息中间捕获事件是一个 等待状态。 在下面的示例中,刘成刚将在 Activity 1 完成后等待消息,在收到消息后执行 Activity 2

message intermediate example

边界消息事件

活动边界上依附的中间捕获消息,或简称 边界消息事件(boundary message event), 捕获与引用的消息定义同名的消息。

图形表示法

边界消息事件可以是可中断的(实双线)或不可中断的(虚双线)。

boundary message event
属性

边界消息事件与消息启动事件的属性相同。

boundary message properties
XML 表示

边界事件在 XML 中做为依附的父活动的子元素。消息事件必须具有 messageRef 属性,引用已有消息定义。

非可中断消息事件具有属性 cancelActivity=false

<task id="Activity_task" name="Task" /> (1)
<boundaryEvent id="interruptible-message-event" name="Message 1" (2)
    attachedToRef="Activity_task">
  <messageEventDefinition id="MessageEventDefinition_1"
    messageRef="messageOne" />
</boundaryEvent>
<boundaryEvent id="non-interruptible-message-event" name="Message 2" (3)
    cancelActivity="false" (4)
    attachedToRef="Activity_task">
  <messageEventDefinition id="MessageEventDefinition_2" messageRef="messageTwo" />
</boundaryEvent>
1  — 消息事件依附的任务。
2  — 可中断的消息事件。
3  — 不可中断的消息事件。
4  — cancelActivity 属性。

使用边界消息事件

消息事件可作为边界事件使用,既可中断,也可以是非中断:

message boundary events

活动可以有多个边界消息事件。

信号事件

信号事件是引用 信号定义 的事件。 广播信号会触发所有匹配的信号事件。 信号具有范围,可以是 Global(全局)Process instance(仅流程定义)

signal events

Jmix BPM 中有下列信号事件:

不支持信号结束事件。请使用 workaround

信号启动事件

信号启动事件(signal start event) 可以使用一个命名的 信号定义 启动流程实例。 流程可以有一个或多个信号启动事件,但信号定义必须不同。

图形表示法

信号启动事件在图中显示为带有信号事件符号的圆圈。如果符号未填充,则表示捕获 (接收) 行为。

signal start event
属性

信号启动事件具有 Signal 属性,指向特定的信号定义。这个是必需属性,否则会导致部署错误。

signal start event properties
XML 表示

信号启动事件的 XML 表示是带有 signalEventDefinition 子元素的普通启动事件:

    <startEvent id="signal-start-event" name="Start">
      <signalEventDefinition id="SignalEventDefinition_00paqo6" (1)
        signalRef="signal-one" /> (2)
      <outgoing>Flow_0h77bcd</outgoing>
    </startEvent>
1  — 事件声明
2  — 特定信号定义

使用信号启动事件

流程部署后,引擎会为每个信号启动事件创建一条信号 订阅。 任何该流程老版本的订阅都将关闭。

允许多个流程定义的信号启动事件引用同一信号。 当信号触发时,将激活所有的订阅并启动流程。

流程实例内可以使用 intermediate signal throw event 触发信号,或者通过 API signalEventReceived 触发。

在 API 调用中,请使用信号的 name,而不是 id。例如,我们有这样的信号定义:

<signal id="ready" name="Ready" flowable:scope="global" />

那么 API 方法可以这样调用:

runtimeService.signalEventReceived("Ready");

嵌入式子流程不支持信号启动事件。

信号中间捕获事件

信号中间捕获事件(Signal intermediate catching event) 捕捉 订阅 的同名信号。 信号中间捕获事件是一个 等待状态

图形表示法

信号中间捕获事件在图中展示为典型的中间事件(双线的圆圈),内部有信号图标。 图标未填充表示“捕获”。

signal intermediate catching event
属性

信号中间捕获事件与信号启动事件的属性相同。

signal catch event properties
XML 表示
<intermediateCatchEvent id="signal-catch-event" name="Catch signal">
      <incoming>Flow_0qwib28</incoming>
      <outgoing>Flow_1itm8do</outgoing>
      <signalEventDefinition id="SignalEventDefinition_1" (1)
        signalRef="signal-one" /> (2)
    </intermediateCatchEvent>
1  — 信号事件声明
2  — 引用信号定义

使用信号捕捉事件

与其他事件(如错误事件)相反,信号捕获了之后不会消费。 如果有两个活动信号边界事件捕获同一个信号事件,则两个边界事件都会触发, 即使位于不同流程实例。

信号中间抛出事件

信号中间抛出事件(intermediate throwing signal event) 会抛出一个信号事件。 抛出的信号会广播至所有的捕获信号事件,包括启动和中间信号 订阅

图形表示法

信号中间抛出事件在图中展示为典型的中间事件(双线的圆圈), 内部有信号图标。 图标已填充表示“抛出”。

signal throwing event
属性

中间信号捕获事件属性与信号启动事件相同, 但语义不同 — 是抛出,而不是捕获。

signal throw event properties

信号发布模式

信号可以同步或异步发布。

  • 在默认配置中,信号是同步传递的。 抛出的流程实例会等待,直到信号发布至所有的捕获流程实例。 捕获流程实例也会在与抛出流程实例相同的事务中得到通知。 也就是说,如果其中一个通知的实例产生技术错误(抛出异常), 所有涉及的实例都会失败。

  • 信号也可以异步传递。 此时,当抛出信号到达时,才确定哪些处理程序处于活动状态。 对于每个活动处理程序,异步通知消息作业(Job)由 JobExecutor 存储和传递。

XML 表示

信号中间事件在 XML 中定义为中间抛出事件。 这里需要使用 signalEventDefinition 子元素。

<intermediateThrowEvent id="Event_sync">
  <signalEventDefinition id="SignalEventDefinition_14tnjbf"
    signalRef="my-signal" /> (1)
</intermediateThrowEvent>


<intermediateThrowEvent id="Event_async">
  <signalEventDefinition id="SignalEventDefinition_14tnjbf"
    signalRef="my-signal" flowable:async="true" /> (2)
</intermediateThrowEvent>
1  — 省略了属性 async,默认为 false,信号同步发布。
2  — 信号异步发布。

错误事件

BPMN 中的错误事件通常用于对流程执行过程中可能出现的异常或错误情况进行建模。 可以依附于 BPMN 图中的活动或子流程,定义应如何处理依附对象的错误。 例如,通过触发错误处理方法,可以记录错误或通知相关参与者。

错误事件有以下类型:

错误启动事件

错误启动事件(error start event) 可用于触发 事件子流程。 不能用于启动流程实例。错误启动事件是中断的(类型)。

图形表示法

错误启动事件在图中展示为带有错误事件符号的圆圈。如果符号未填充,则表示捕获 (接收) 行为。

error start event
属性

错误启动事件有一个特殊的属性 — Error,引用某些 错误定义

与消息和信号不同,错误定义不是必须设置。 如果没有设置错误定义,则发生的每个错误事件都可以启动子流程。

error start event properties
XML 表示

错误启动事件的 XML 表示是带有 errorEventDefinition 子元素的常规启动事件声明:

  <startEvent id="error-event" name="Error">
    <errorEventDefinition id="ErrorEventDefinition_1" (1)
        errorRef="failure" /> (2)
  </startEvent>
1  — 错误事件声明
2  — 设置错误定义。

示例

在下面示例中,第一个任务以编程方式生成 BPMN 错误。 此时,事件子流程会启动,完成后,主流程将终止。

error start event example

错误边界事件

错误边界事件(error boundary event) 可以捕获在依附的活动范围内抛出的错误。

图形表示法

错误边界事件在图中显示为边界上的中间事件(双线的圆圈), 内部有错误图标。 错误图标未填充以表示“捕获”(型)。

error boundary event
属性

错误边界事件与错误启动事件具有相同的属性。

error boundary event properties
XML 表示
<serviceTask id="Activity_1" name="Check error"
. . .
</serviceTask>
<boundaryEvent id="error-boundary-event" name="Error"
    attachedToRef="Activity_1">
  <errorEventDefinition id="ErrorEventDefinition_1"
    errorRef="failure" />
</boundaryEvent>

错误结束事件

当流程执行到 错误结束事件(error end event) 时,当前流程路径将结束并抛出错误。

图形表示法

错误结束事件在图中显示为典型的结束事件(粗线的圆圈),内部有错误图标。 错误图标已填充表示“抛出”。

error end event
属性

错误结束事件有一个特殊的属性 — Error,该属性非必需。 如果设置,则需要引用某些已存在的 错误定义

error end event properties
XML 表示

错误结束事件在 XML 以结束事件表示,带 errorEventDefinition 子元素。

<endEvent id="Event_01" name="Error">
  <incoming>Flow_1i3jqxp</incoming>

  <errorEventDefinition id="ErrorEventDefinition_11xfxfw" (1)
    errorRef="failure" /> (2)
</endEvent>
1  — 声明错误事件
2  — 设置错误定义,可以省略。

使用错误结束事件

错误结束事件(error end event) 是一个抛出事件,必须有对应的捕获事件。 如果错误结束事件属于某个子流程,捕获事件可以是错误边界事件。

error end event in subprocess

捕获事件也可以是错误启动事件,如果有子流程的话。

error end event with event subprocess

使用无捕获错误事件的错误结束事件会导致运行时错误。

error end event bad example

参阅 错误处理 部分。

补偿事件

补偿事件可以撤销流程中已成功完成的步骤, 以修复这些步骤的结果。

补偿事件的类型:

补偿中间抛出事件

补偿中间抛出事件(Compensation intermediate throwing event) 可用于触发补偿。

触发补偿

可以为指定的活动触发补偿,也可以为补偿事件依附的范围触发补偿。 补偿行为是通过执行与活动关联的补偿处理逻辑来完成。

当为活动抛出补偿时, 关联的补偿处理逻辑的执行次数与活动成功完成需要执行的次数相同。

如果为当前范围抛出补偿,则当前范围内的所有活动都会得到补偿。 包括并发分支上的活动。

补偿按层次结构触发: 如果要补偿的活动是子流程, 则为子流程中包含的所有活动触发补偿。 如果子流程具有嵌套的内部活动,则以递归方式抛出补偿。 但是,补偿不会传播到流程的“上层”: 即,如果是在子流程内触发的补偿,则不会传播到子流程范围之外的活动。 BPMN 规范指出,补偿是针对“同一级别的子流程”的活动触发的。

在 Flowable 中,补偿按流程执行的相反顺序执行。也就是说,最后完成的那个活动,将首先得到补偿,依此类推。

中间抛出补偿事件可用于补偿成功完成的事务子流程。

图形表示法

中间补偿抛出事件在图中展示为典型的中间事件(双线圆圈), 内部有补偿图标。 补偿图标已填充以表示“抛出”。

compensation throwing event
属性

补偿抛出事件无特定属性。

compensation throwing event properties
XML 表示

补偿中间事件在 XML 中定义为中间抛出事件。此时需使用 compensateEventDefinition 子元素。

<intermediateThrowEvent id="throwCompensation">
  <compensateEventDefinition id="CompensateEventDefinition_0s3nsqo" />
</intermediateThrowEvent>

此外,可选参数 activityRef 可用于触发特定范围或活动的补偿:

<intermediateThrowEvent id="throwCompensation">
    <compensateEventDefinition id="CompensateEventDefinition_0s3nsqo"
        activityRef="bookHotel" /> (1)
</intermediateThrowEvent>
1  — 为特定活动触发补偿。

示例

如果在包含子流程的范围内触发了补偿,并且该子流程包含带补偿处理逻辑的活动, 则当抛出补偿时,只有子流程已成功完成,补偿才会传播到子流程中。

如果在子流程内部的某些活动已经完成并具有依附的补偿处理逻辑, 则子流程本身尚未完成时,不会执行这些处理逻辑。 参考下面示例:

compensation example

在这个流程中,我们有两个并发分支:一个是嵌入式子流程,另一个是 “charge credit card” 活动。 假设两个分支都已启动,并且第一个分支正在等待用户完成 “review bookings” 任务。

第二个分支在执行 “charge credit card” 活动,在这个活动中发生错误 触发 “cancel booking” 事件以启动补偿。

此时,第一分支的子流程尚未完成,也就是说补偿没有传递到这个分支。 因此,不会执行 “cancel hotel booking” 补偿处理逻辑。

如果用户任务(以及嵌入子流程)在 “cancel booking” 操作之前完成, 补偿将传播到嵌入子流程中。

补偿边界事件

补偿边界事件(Compensation boundary event) 可用于将补偿处理逻辑依附至活动。

补偿边界事件必须有方向地关联单个补偿处理逻辑。

补偿边界事件具有与其他边界事件不同的激活策略。 其他边界事件(比如信号边界事件)在所依附的活动启动时被激活。 活动完成后,这些边界事件将被禁用,并取消相应的事件订阅。

而补偿边界事件则不同。 补偿边界事件在所依附的活动成功完成时激活。 此时,才创建补偿事件的相应订阅。 当触发补偿事件或对应的流程实例结束时,删除订阅。 因此,其逻辑如下:

  • 当补偿触发时,与补偿边界事件关联的补偿处理逻辑会被调用,其调用次数与所依附的活动成功完成的次数相同。

  • 如果一个补偿边界事件所依附的活动具有 多实例 特性,则会为每个实例创建一个补偿事件的订阅。

  • 如果流程实例结束,会取消所有补偿事件的订阅。

嵌入式子流程不支持补偿边界事件。

图形表示法

补偿边界事件在图中显示为边界上的典型中间事件(双线圆圈),内部有补偿图标。补偿图标未填充以表示“捕获”。 除了补偿边界事件之外,下图显示了补偿处理逻辑与边界事件的单向关联。

补偿边界事件必须有向关联至单一补偿处理逻辑。

compensation boundary event
XML 表示

补偿边界事件在 XML 中定义为典型的边界事件:

<boundaryEvent id="Event_1" attachedToRef="Activity_1">
  <compensateEventDefinition id="CompensateEventDefinition_05" />
</boundaryEvent>

. . .

<association id="Association_02zt79e"
associationDirection="One"
sourceRef="Event_1" targetRef="Activity_1" />

取消事件

取消事件仅在 事务子流程 中使用。 只有在事务子流程中,才可以从工具箱找到取消事件。

有两种类型的取消事件:

取消结束事件

取消结束事件(cancel end event) 只能与 BPMN 事务子流程 结合使用。当流程到达取消结束事件事件时,将抛出一个取消事件,该事件必须由取消边界事件捕获。然后,取消边界事件取消当前事务并触发补偿。

图形表示法

取消结束事件在图中显示为典型的结束事件(粗线圆圈),内部带有取消图标。取消图标完全为黑色,表示“抛出”。

cancel end event
XML 表示

取消结束事件在 XML 中表示为带 cancelEventDefinition 子元素的结束事件。

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

取消边界事件

一个依附在事务子流程边界的 中间捕获取消事件(intermediate catching cancel event),简称 取消边界事件(boundary cancel event),当事务被取消时触发。

当触发取消边界事件时,首先会中断当前范围内的所有激活的执行分支。 然后,为事务范围内的所有激活的补偿边界事件启动补偿。

补偿是同步执行的,边界事件在离开事务之前会等待补偿完成。 当补偿完成时,使用取消边界事件的出口顺序流,离开事务子流程。

  • 一个事务子流程只允许一个取消边界事件。

  • 如果事务子流程中有嵌套的子流程,只有成功完成的子流程才会触发补偿。

  • 如果取消边界事件放置在具有多实例特性的事务子流程上,如果一个实例触发了取消,则边界事件将取消所有实例。

图形表示法

取消边界事件,用内部有一个取消图标的标准中间事件(双线圆圈)表示。取消图标是白色的(未填充),代表“捕获”。

cancel boundary event
XML 表示

取消边界事件的 XML 定义为一个典型的边界事件:

<boundaryEvent id="boundary" attachedToRef="transaction" >
    <cancelEventDefinition />
</boundaryEvent>

由于取消边界事件是中断的,因此 cancelActivity 属性不是必需。

终止结束事件

当到达 终止结束事件(terminate end event) 时,当前的流程实例或子流程会被终止。

图形表示法

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

terminate end event
XML 表示

终止结束事件在 XML 中为结束事件,带有 terminateEventDefinition 子元素。

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

terminateAll 属性可选(默认为 false)。

使用终止结束事件

在这个示例中,我们可以看到并行执行的两个用户任务。 如果任务 #2 首先完成,则执行将到达终止结束事件。 此时,任务 #1 将被删除,即使仍然处于活动状态。

terminate end event example

在下一个示例中,终止结束事件位于子流程中。当达到时,仅影响子流程。 因此,如果任务 #1 处于活动状态,则将被删除,子流程将被终止,主流程则以正常方式继续。

terminate end event example 2

BPMN 事件覆盖度

在 Jmix BPM 中,并非支持所有的 BPMN 2.0 事件,不支持的事件以粉红色标记。 也就是说,虽然 BPMN 2.0 标准定义了广泛的事件, 但 Jmix BPM 集成了 Flowable 引擎,该引擎可能没有实现标准中所有的事件类型。

jmix events

不支持的事件

  • 消息抛出的中间和结束事件

  • 信号抛出结束事件

  • 补偿结束事件

  • 升级事件(Escalation events)的全部类型

  • 条件事件(Conditional events)的全部类型

  • 连接事件(Link events)的全部类型

从第三方设计工具导入 BPMN 模型时要小心: 不支持的事件虽然可以显示在关系图上,但可能会在运行时发生错误。

不支持事件的解决方法

在本节中,我们介绍如何为 Jmix BPM 中不支持的元素实现所需流程逻辑。

消息抛出事件

首先,在建模中,尽量使用 信号 代替 消息。多数情况下,这两种事件可以互换。

signal instead of message

然后,使用服务任务调用 API。

throw message workaround 1

服务任务可以实现为 Spring bean,示例:

@Component(value = "smpl_MyService")
public class MyService {

    @Autowired
    private RuntimeService runtimeService;

    public void sendMessage(String messageName, String executionId) {
        runtimeService.messageEventReceived(messageName, executionId);
    }
}

信号抛出结束事件

使用 信号抛出中间事件空结束事件 的组合替换:

workaround signal end event

补偿结束事件

compensation end event workaround

升级事件

在某些情况下,可以使用 BPMN 错误事件替代升级事件(escalation events)。 BPMN 中的错误事件用于处理流程执行期间发生的错误或异常。 可用于对流程中的错误处理和恢复机制进行建模。

另一方面,升级事件用于将问题上报到组织或流程层次结构中的更高级别。 当问题无法在当前级别解决并且需要升级以采取进一步措施时,通常会使用升级事件。

因此,升级事件在技术上非常接近错误事件。

workaround escalation events

条件事件

条件事件定义当给定的条件计算结果为 true 时会触发的事件。 可以用作事件子流程的启动事件,也可以用作中间事件和边界事件。 启动和边界事件可以是中断或非中断。

可以将信号或消息事件与执行监听器结合使用实现类似的逻辑。

workaround conditional events

不要使用连接事件。

从 Camunda 建模器等第三方工具导入 XML 文件时,连接事件可能会出现在图中。