边界事件

本文中内容和案例节选自贺波老师的《深入Activiti流程引擎:核心原理与高阶实战》一书。这本书中的内容更为全面、详尽,对系统学习和深入掌握Activiti/Flowable的用法非常有帮助,推荐给大家。

QQ交流群1:633168411 已满
QQ交流群2: 582010059

参照本书录制的讲解视频地址

博客地址

在BPMN2.0的事件分类中,边界事件被划分到中间事件中,BPMN2.0中将狭义的中间事件和边界事件,统称为中间事件。Flowable所称的中间事件为狭义的中间事件,即可以单独作为流程元素存在于流程中的事件为中间事件,而附属于某个流程元素(如任务、子流程等)的事件为边界事件。边界事件是Catching事件,会等待被触发,当边界事件被触发,当前的活动会被中断,并且当前的顺序流会发生转移。

附属于某个流程元素(如任务、子流程等)的事件为边界事件。边界事件是捕获事件,会等待 被触发,当边界事件被触发,当前的活动会被中断,并且当前的顺序流会发生转移。

在 Flowable 中,结束事件可以划分为以下几种类型:

  • 消息边界事件(Message Boundary Interrputing Event)
  • 信号边界事件(Signal Boundary Interrputing Event)
  • 错误边界事件(Error Boundary Interrputing Event)
  • 定时边界事件(Timer Boundary Interrputing Event)
  • 取消边界事件(Cancel Boundary Interrputing Event)
  • 补偿边界事件(Compensate Boundary Interrputing Event)

根据捕获后对路线影响的不同行为,又分为两种:

  1. 边界中断事件,附加的活动(任务)实例被终止,执行该事件的后继路线。
  2. 边界非中断事件,附加的活动(任务)实例继续执行,同时执行该事件的后继路线。

消息边界事件

定义

消息边界事件会捕获消息定义引用的相同信息名的信息。当执行到达边界消息事件依附的任务 时(如用户任务、子流程),引擎会创建一个捕获事件,在其依附的任务的生命周期内等待一个抛 出消息,该消息来自消息抛出事件或者 API,被触发后后继路线继续执行。

图形标记

边界消息事件显示成一个普通的中间事件(圆圈里有个小圆圈),位于节点边缘,内部是一个 消息小图标。消息图标是白色(无填充),表示捕获语义,如图所示

边界消息事件可能是中断(左侧)或非中断(右侧)的。

XML内容

<message id="theMessage" name="newInvoiceMessage" />
<process id="messageBoundaryInterrputingEventProcess">
    <userTask id="usertask1" name=" "></userTask>
    <boundaryEvent id="messageBoundaryInterrputingEvent" name="Timer"
    attachedToRef="usertask1" cancelActivity="false">
        <messageEventDefinition messageRef="theMessage" />
    </boundaryEvent>
<!-- -->
</process>

在以上 xml 代码片段中,加粗的部分分别定义了 message、userTask 和 boundaryEvent,消息 message 的 id 属性值为 theMessage,消息边界事件 boundaryEvent 中的 messageEventDefinition 子元 素通过设置 messageRef 为 theMessage 引用了该信号,同时使用 attachedToRef 属性将其绑定到 userTask 上。cancelActivity 属性用法与定时边界事件相同。 这里是将消息边界事件附加在了用户任务节点上,其它流程活动(如子流程等)也可以附加。

使用示例

消息边界事件触发的方式有两种:

  1. 流程中抛出消息事件(Message Intermediate Throwing Event)、消息结束事件(Message EndEvent)发出的内部消息。
  2. 通过 API 触发,在 Flowable 中通过调用 runtimeService.messageEventReceived 系列方法发出一个指定的信号。runtimeService.messageEventReceived 系列方法下表格所示:
API 方法含义
runtimeService.messageEventReceived(String messageName, String executionId)把消息发送给指定执行流
runtimeService.messageEventReceived(String messageName, String executionId, HashMap<String, Object> processVariables)把消息发送给指定执行流,同时给更新流程变量

界面操作

演示demo

消息边界事件

信号边界事件

定义

信号边界事件会捕获信号定义引用的相同信号名的信号。当执行到达边界信号事件依附的任务 时(如用户任务、子流程等),引擎会创建一个捕获事件,在其依附的任务的生命周期内等待一个 抛出信号,该信号可以来自流程的信号抛出事件,或者由 API 触发,被触发后流程会沿信号边界 事件的后继路线继续执行。

图形标记

信号边界事件显示为普通的中间事件(圆圈里有个小圆圈),位置在节点的边缘,内部有一个 信号小图标。信号图标是白色的(未填充),来表示捕获的意思,如下图所示

XML内容

 <signal id="theSignal" name="The Signal" />
 <process id="signalBoundaryInterrputingEventProcess">
    <userTask id="usertask1" name="测试信号任务"></userTask>
    <boundaryEvent id="signalBoundaryInterrputingEvent" name="Timer" 
    attachedToRef="usertask1" cancelActivity="false"> 
        <signalEventDefinition signalRef="theSignal"/> 
    </boundaryEvent>
 </process>

在以上 xml 代码片段中,加粗的部分分别定义了 signal、userTask 和 boundaryEvent,信号 signal 的 id 属性值为 theSignal,信号边界事件 boundaryEvent 中的 signalEventDefinition 子元素通过设置 signalRef 为 theSignal 引用了该信号,同时使用 attachedToRef 属性将其绑定到 userTask 上。 cancelActivity 属性用法与定时边界事件相同。 这里是将信号边界事件附加在了用户任务节点上,其它流程活动(如子流程等)也可以附加。 信号边界事件接收到指定的信号后就会触发。需要注意的是,信号事件是全局的,即在一个流 程实例中抛出一个信号事件,其他不同流程定义的流程实例都可以监听到这个事件(一处发信号, 所有信号的边界事件都能接收)。如果想要限制信号事件的范围,只希望在同一个流程实例中响应 这个信号事件,可以使用信号事件定义的 scope 属性(不是 BPMN2.0 的标准属性):

<signal id="alertSignal" name="alert" flowable:scope="processInstance"/>

其中,flowable:scope 的默认值是 global,代表全局;设置为 processInstance 时,作用范围仅仅 是在发生事件的流程实例里。

使用示例

信号边界事件的触发条件是接收信号,它具有全局性,可以捕获流程引擎内全局范围的信号。 信号边界事件触发的方式有两种:
(1)流程中抛出信号事件(Signal Intermediate Throwing Event)、信号结束事件(Signal End Event)发出的信号。
(2)通过 API 触发,在 Flowable 中通过调用 runtimeService.signalEventReceived 系列方法发出一 个指定的信号。runtimeService.signalEventReceived 系列方法如下图所示:

API 方法含义
runtimeService.signalEventReceived(String signalName)把信号发送给全局所有订阅的处理器
runtimeService.signalEventReceived(String signalName, String executionId)把信号发送给指定执行流

界面操作

演示demo

信号边界事件

错误边界事件

定义

错误边界事件依附在某个流程活动中,用于捕获节点范围内抛出的错误,一般用在嵌入子流程 或者调用活动,也可以用于其它节点。当错误边界事件依附的节点抛出 BPMNError 业务异常时销 毁该活动,错误边界事件自动被激活,流程执行会继续沿着错误边界事件的外出顺序流继续执行。

图形标记

错误边界事件显示成一个普通的中间事件(圆圈内部有一个小圆圈)放在节点的标记上,内部 有一个错误小图标。错误小图标是白色的,表示它是一个捕获事件,如下图所示:

XML内容

错误边界事件的 XML 内容是普通边界事件的声明,包含一个错误定义子元素:

 <error id="theError" errorCode="410" />
 <process id="messageBoundaryInterrputingEventProcess">
    <userTask id="usertask1" name=" "></userTask>
    <boundaryEvent id="errorBoundaryInterrputingEvent" name="Timer" 
    attachedToRef="usertask1" cancelActivity="false"> 
     <errorEventDefinition errorRef="theError"></errorEventDefinition> 
    </boundaryEvent>
</process>

使用示例

错误边界事件通过设置 errorRef 属性引用错误信号,错误信号的 errorCode 用于查找匹配的错 误捕获边界事件。具体规则是这样的:

  1. 如果设置了 errorRef,并引用了一个已定义的错误,边界事件就只捕获错误代码与之相同的错误。
  2. 如果设置了 errorRef,但不匹配任何已定义的错误,errorRef 就会当做 errorCode 使用。
  3. 如果没有设置 errorRef,错误边界事件将会捕获任何错误事件,无论错误的 errorCode 是什么。

界面操作

注意

  • 当错误边界事件依附于子流程时,它会为所有子流程内部的节点创建一个作用范围。
  • 当子流程的错误结束事件抛出的错误时,这个错误会往上层作用域传递,直到找到一个错误事件定义匹配的错误边界事件。

演示demo

错误边界事件

边界补偿事件

定义

补偿边界事件可以为所依附的节点附加补偿处理器,通过关联连接到补偿处理器(compensation handler)。补偿边界事件会在流程活动完成后根据情况(事务取消或者补偿中间事件触发)而触发, 当补偿边界事件触发时,执行它连接的补偿处理器。

补偿边界事件必须直接引用一个相关的补偿处理器。如果要使用一个活动补偿另一个活动的影 响,可以将其声明为补偿处理器(compensation handler)。补偿执行是通过活动附加的补偿边界事 件所关联的补偿处理器的 execution 来完成的。

图形标记

补偿边界事件显示为了一个普通的中间事件(内部有小圈的圆),里面有补偿图标。补偿图标 是白色的(无填充),表明是捕获语义。取消边界事件图标如下图所示,图中还显示了使用无 方向的关联,为边界事件设置补偿处理器:

XML内容

补偿边界事件的 XML 内容是普通边界事件的声明,包含一个 compensateEventDefinition 子元 素:

 <process id="compensateBoundaryEventProcess">
    <userTask id="usertask1" name="审批"></userTask>
    <!-- 定义边界补偿-->
     <boundaryEvent id="compensateBoundaryEvent1" name="Compensate" 
    attachedToRef="usertask1"> 
     <compensateEventDefinition>
     </boundaryEvent>
    <!--  定义补偿处理器 -->
     <serviceTask id="serviceTask1" name="CompensationHandler" isForCompensation="true"
    flowable:class="**.**.**.****"></serviceTask>
    <!-- 定义关联 -->
     <association id="association1" sourceRef="compensateBoundaryEvent1" 
    targetRef="serviceTask1" associationDirection="None"/>
 </process>

注意,附加的补偿事件通过关联连接到补偿处理器,而不是通过序列流连接到补偿处理器。

使用示例

补偿边界事件与其它边界事件的行为策略不同,其它边界事件(比如信号边界事件)在其附加 活动到达时即被激活,当活动结束时,它也结束了,并且对应的事件订阅也会被取消。而补偿边界 事件与它们不同,补偿边界事件在附加活动成功完成后才激活,并创建相应的边界事件订阅。当补 偿边界事件触发或对应流程实例结束时,事件订阅才会删除。

在 Flowable 中,当执行流到达附加边界事件的活动时,会往 ACT_RU_EVENT_SUBSCR 表入事 件描述数据,边界事件所依附的活动完成后,这些事件描述数据会被删除,但是补偿边界事件所产 生的事件描述数据不会被删除(直到流程实例结束),因为即使活动完成后,这些补偿事件都有可 能被触发。

1、补偿边界事件使用时遵循以下规则:

  • 当补偿被触发时,所有已成功完成的活动上附加的补偿边界事件对应的补偿处理器将被调 用,如果补偿边界事件依附活动尚未产生历史任务,则不会被触发。
  • 附有补偿边界事件的活动完成若干次,那么当补偿边界事件触发后,这些补偿边界事件的执 行次数与活动的完成次数相等。
  • 如果补偿边界事件依附在到多实例节点,则会为每个实例创建补偿事件订阅,补偿被触发的 次数与依附节点的循环多例任务的成功完成次数相等。
  • 如果补偿边界事件依附的节点中包含循环,则每次执行活动时都会创建一个补偿事件订阅。
  • 如果流程实例结束,订阅的补偿事件都会结束。
  • 补偿边界事件不支持依附在内嵌子流程中。

2、补偿边界事件关联的补偿处理器需要注意以下几点:

  • 补偿处理器不得有入口或出口顺序流。
  • 补偿处理器必须通过单向的关联,连接到一个补偿边界事件。
  • 要将一个活动声明为补偿处理器,需要将 isForCompensation 属性设置为 true,如。 ⑷补偿处理器不在正常流程中执行,而只在流程抛出补偿事件时才会执行。

注意

1、事务子流程被取消时,导致依附在事务子流程中的活动上的补偿边界事件触发。这种方式的示例请查看子流程中的事务子流程部分。
2、使用补偿中间事件来触发,导致补偿边界事件触发。这种方式的示例请查看本章补偿中间事件部分。

演示demo

补偿边界事件

定时器边界事件

定义

定时器边界事件是附属在流程活动(如用户任务、系统任务、子流程)中的事件,当流程到达 了流程活动时,引擎会创建一个定时器,当定时器触发后,流程会沿定时边界事件的后继路线继续 执行

注意 使用定时器事件需要开启flowable的作业执行器 configuration.setAsyncExecutorActivate(true);

图形标记

定时边界事件是一个标准的边界事件(边界上的一个圆圈),内部是一个定时器小图标,如下图所示:

也分为中断和非中断的

XML内容

定时边界事件的 XML 内容是普通边界事件的声明,包含一个定时器事件子元素:

 <process id="timerBoundaryEventProcess">
    <userTask id="usertask1" name="审批"></userTask>
    <boundaryEvent id="timerBoundaryEvent" name="Timer" attachedToRef="usertask1" 
    cancelActivity="false"> 
     <timerEventDefinition> 
     <timeDuration>PT1M</timeDuration> 
     </timerEventDefinition> 
     </boundaryEvent>
 </process>

定义定时器的标签是<timerEventDefinition>...</timerEventDefinition>,它必须具有以下一个元 素:timeDate,timeDuration,timeCycle。

1. timeDate:设置在指定时间触发。

    <startEvent id="timerStart">
        <timerEventDefinition>
           <timeDate>2023-07-14T12:12:14</timeDate>
        </timerEventDefinition>
    </startEvent>

timeDate 是使用 ISO 8601 格式指定一个确定的时间来触发事件,以上配置表示流程会在 2023-07-14T12:12:14 启动起来。

注意:ISO8601 时间格式,如果要加时间需要前面加 T。

2、timeDuration:置指定一个时间段之后执行。

timeDuration 是指定定时器之前要等待多长时间。S 表示秒,M 表示分,D 表示天;P 表示时 间段,T 表示精确到时间的时间段。

注意:时间格式依然为 ISO 8601 格式,一年两个月三天四小时五分六秒内,可以写成 P1Y2M3DT4H5M6S,P 是开始标记,T 是时间和日期分割标记,没有日期只有时间 T 是不能省去 的,比如 1 小时执行一次应该写成 PT1H。

3、通过 timeCycle 设置指定定时器的运行周期

timeCycle 指定重复执行的间隔,可以用来定期启动流程实例。timeCycle 的设置目前有两种方 式:ISO 8601 和 Cron 表达式。R 表示需要执行的次数,R2/PT1M 表示执行两次,每次间隔 1 分钟。 其中 endDate 是可选的配置,定时器将会在指定的时间停止工作。

注意:使用定时器开始事件需要启动 JobExecutor

使用示例

设计一个客户投诉处理的流程,收到客户投诉,先由一线客服人员处理,如果超过 2 个小时一 线客服仍然未能办结,就交由二线客服人员处理,此时可以为一线客服的流程任务加入定时边界事 件。

界面操作

演示demo

定时器边界事件

取消边界事件

定义

附加在事务性子流程的边界上的中间捕获取消事件,简称边界取消事件,它在事务取消时触发。 当取消边界事件触发时,首先会中断当前作用域中的所有活动的执行,然后开始执行补偿所有在这 个事务的作用域内的活动的补偿边界事件。补偿是同步执行的,意味着边界事件会一直等待到补偿 事件完成后才会离开事务,当补偿完成后,事务子流程会沿着取消边界事务的外出连线继续执行。

图形标记

取消边界事件显示为了一个普通的中间事件(内部有小圈的圆),里面有取消图标。取消图标 是白色(无填充),表明是捕获语义。取消边界事件图标如下图所示:

XML内容

 <process id="cancelBoundaryEventProcess">
    <transaction id="transactionSubProcess" name=" ">
    </transaction>
    <boundaryEvent id="cancelBoundaryEvent" name="Cancel" 
    attachedToRef="transactionSubProcess"> 
     <cancelEventDefinition />
     </boundaryEvent>
 </process>

使用示例

由于取消边界事件是跟事务子流程搭配使用的,具体的查看子流程中有关事务 子流程的部分。取消边界事件使用时需要注意以下几点:

  • 每个事务子流程只能有一个取消边界事件。
  • 如果事务子流程包含嵌套的子流程,当取消边界事件触发时,补偿只会触发已经成功完成的 子流程。
  • 如果取消边界子流程对应的事务子流程配置为多实例,如果其中一个实例触发消边界事件, 所有的实例都会取消。

演示demo

取消边界事件

条件边界事件

敬请期待

边界升级事件

敬请期待

边界打包事件

敬请期待

边界注册事件

敬请期待