工作流中各个元素介绍之工作流开始和结束事件详解

开始事件

  • 开始事件用来指明流程在哪里开始
  • 开始事件的类型(流程在接收事件时启动,还是在指定时间启动...),定义了流程如何启动, 这通过事件中不同的小图表来展示.在XML中,这些类型是通过声明不同的子元素来区分
  • 开始事件都是捕获事件: 最终这些事件都是一直等待着,直到对应的触发时机出现
  • 在开始事件中,可以设置activiti特定属性:
    • initiator: 当流程启动时,把当前登录的用户保存到指定的变量名中:
    <startEvent id="request" activiti:initiator="initiator" />
    
    • 登录的用户必须使用IdentityService.setAuthenticatedUserId(String) 方法设置,并包含在try-finally代码中:
 try {
 identityService.setAuthenticatedUserId("bono");
 runtimeService.startProcessInstanceByKey("someProcessKey");
} finally {
 identityService.setAuthenticatedUserId(null);
}

空开始事件

描述
  • 空开始事件技术上意味着没有指定启动流程实例的触发条件
  • 引擎不能预计什么时候流程实例会启动
  • 空开始事件用于: 当流程实例要通过API启动的场景,通过调用startProcessInstanceByXXX方法
  • 子流程都有一个空开始事件
ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();
图形标记
  • 空开始事件显示成一个圆圈.没有内部图表,即没有触发类型


    在这里插入图片描述
XML结构
  • 空开始事件的XML结构是普通的开始事件定义 ,没有任何子元素
  • 其他开始事件类型都有一个子元素来声明自己的类型
<startEvent id="start" name="my start event" />
空开始事件的自定义扩展
  • formKey: 引用用户在启动新流程实例时需要填写的表单模板
<startEvent id="request" activiti:formKey="org/activiti/examples/taskforms/request.form" />

定时开始事件

描述
  • 定时开始事件用来在指定的时间创建流程实例: 可以同时用于只启动一次的流程和应该在特定时间间隔启动多次的流程
  • ==注意:==
    • 子流程不能使用定时开始事件
    • 定时开始事件在流程发布后就会开始计算时间
      • 不需要调用startProcessInstanceByXXX, 虽然也可以调用启动流程的方法,但是那会导致调用startProcessInstanceByXXX时启动过多的流程
    • 当包含定时开始事件的新版本流程部署时, 对应的上一个定时器就会被删除. 这是因为通常不希望自动启动旧版本流程的流程实例
图形标记
  • 定时开始事件显示为一个圆圈,内部是一个表:


    在这里插入图片描述
XML内容
  • 定时开始事件的XML内容是普通开始事件的声明,包含一个定时定义子元素
        <startEvent id="theStart">
            <timerEventDefinition>
                <!--流程会启动4次,每次间隔5分钟,从2011年3月11日,12:13开始计时-->
                <timeCycle>R4/2011-03-11T12:13/PT5M</timeCycle>
            </timerEventDefinition>
        </startEvent>
        <startEvent id="theStart">
            <timerEventDefinition>
                <!--流程会根据选中的时间启动一次-->
                <timeDate>2011-03-11T12:13:14</timeDate>
            </timerEventDefinition>
        </startEvent>

消息开始事件

描述
  • 消息开始事件可以使用一个命名的消息来启动流程实例,这样可以使用消息名称来选择正确的开始事件
  • 在发布包含一个或多个消息开始事件的流程定义时:
    • 消息开始事件的名称在给定流程定义中不能重复:
      • 流程定义不能包含多个名称相同的消息开始事件
      • 如果两个或以上消息开始事件应用了相同的事件
      • 或两个或以上消息事件引用的消息名称相同
      • activiti会在发布流程定义时抛出异常
    • 消息开始事件的名称在所有已发布的流程定义中不能重复:
      • 如果一个或多个消息开始事件引用了相同名称的消息
      • 而这个消息开始事件已经部署到不同的流程定义中
      • activiti就会在发布时抛出一个异常
    • 在发布新版本的流程定义时,之前订阅的消息订阅会被取消:
      • 如果新版本中没有消息事件也会这样处理
  • 启动流程实例,消息开始事件可以使用RuntimeService中的方法来触发:
ProcessInstance startProcessInstanceByMessage(String messageName);
ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object< processVariables);
  • 这里的messageNamemessageEventDefinitionmessageRef属性引用的message元素的name属性
  • 启动流程实例时,要考虑以下因素:
    • 消息开始事件只支持顶级流程,消息开始事件不支持内嵌子流程
    • 如果流程定义有多个消息开始事件, runtimeService.startProcessInstanceByMessage(...) 会选择对应的开始事件
    • 如果流程定义有多个消息开始事件和一个空开始事件. runtimeService.startProcessInstanceByKey(...)和 runtimeService.startProcessInstanceById(...)会使用空开始事件启动流程实例
    • 如果流程定义有多个消息开始事件,但是没有空开始事件, runtimeService.startProcessInstanceByKey(...)和 runtimeService.startProcessInstanceById(...)会抛出异常
    • 如果流程定义只有一个消息开始事件, runtimeService.startProcessInstanceByKey(...)和 runtimeService.startProcessInstanceById(...)会使用这个消息开始事件启动流程实例
    • 如果流程被调用环节(callActivity)启动,消息开始事件只支持如下情况:
      • 在消息开始事件以外,还有一个单独的空开始事件
      • 流程只有一个消息开始事件,没有空开始事件
图形标记
  • 消息开始事件是一个圆圈,中间是一个消息事件图标.图标是白色未填充的,来表示捕获(接收)行为


    -
XML内容
  • 消息开始事件的XML内容在普通开始事件中,包含一个messageEventDefinition子元素:
<definitions id="definitions"
  xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:activiti="http://activiti.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>

信号开始事件

描述
  • 信号开始事件可以通过一个已命名的信号(signal)来启动一个流程实例
    • 信号可以在流程实例内部使用中间信号抛出事务触发
    • 也可以通过API(runtimService.signalEventReceivedXXX)触发
    • 两种情况下,所有流程实例中拥有相同名称的signalStartEvent都会启动
    • 两种情况下,都可以选择同步或异步的方式启动流程实例
  • 必须向API传入signalName, 这是signal元素的name属性值,它会被signalEventDefinitionsignalRef属性引用
图形标记
  • 信号开始事件显示为一个中间包含信号事件图标的圆圈.标记是无填充的,表示捕获(接收)行为


    在这里插入图片描述
XML格式
  • signalStartEvent的XML格式是标准的startEvent声明,其中包含一个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>

错误开始事件

描述
  • 错误开始事件可以用来触发一个事件子流程.错误开始事件不能用来启动流程实例
  • 错误开始事件都是中断事件
图形标记
  • 错误开始事件是一个圆圈,包含一个错误事件标记.标记是白色未填充的,来表示捕获(接收)行为


    在这里插入图片描述
XML内容
  • 错误开始事件的XML内容是普通开始事件定义中,包含一个 errorEventDefinition子元素
<startEvent id="messageStart" >
        <errorEventDefinition errorRef="someError" />
</startEvent>

结束事件

  • 结束事件表示(子)流程(分支)的结束
  • 结束事件都是触发事件:
    • 流程达到结束事件,会触发一个结果
    • 结果的类型是通过事件的内部黑色图标表示的
    • 在XML内容中,通过包含的子元素声明

空结束事件

描述
  • 空结束事件意味着到达事件时不会指定抛出的结果
  • 引擎会直接结束当前执行的分支,不会做其他事情
图形标记
  • 空结束事件是一个粗边圆圈, 内部没有小图标(无结果类型)
    在这里插入图片描述
XML内容
  • 空结束事件的XML内容是普通结束事件定义
  • 不包含子元素,其他结束事件类型都会包含声明类型的子元素
<endEvent id="end" name="my end event" />

错误结束事件

描述
  • 当流程执行到错误结束事件 ,流程的当前分支就会结束,并抛出一个错误
  • 这个错误可以被对应的中间边界错误事件捕获.如果找不到匹配的边界错误事件,就会抛出一个异常
图形标记
  • 错误结束事件是一个标准的结束事件 -粗边圆圈, 内部有错误图标, 错误图标是全黑的,表示触发语法
    在这里插入图片描述
XML内容
  • 错误结束事件的内容是一个错误事件, 子元素为errorEventDefinition
<endEvent id="myErrorEndEvent">
  <errorEventDefinition errorRef="myError" />
</endEvent>
  • errorRef属性引用定义在流程外部的error元素:
<error id="myError" errorCode="123" />
...
<process id="myProcess">
...
  • error的errorCode用来查找匹配的捕获边界错误事件
  • 如果errorRef与任何error都不匹配,就会使用errorRef来作为errorCode的缩写. 这是activiti特定的缩写:
<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格式相符,必须是一个合法的QName

取消结束事件

描述
  • 取消结束事件只能与BPMN事务子流程结合使用
  • 当到达取消结束事件时,会抛出取消事件 ,它必须被取消边界事件捕获
  • 取消边界事件会取消事务,并触发补偿机制
图形标记
  • 取消结束事件显示为标准的结束事件-粗边圆圈,包含一个取消图标.取消图标是全黑的,表示触发语法


    在这里插入图片描述
XML内容
  • 取消结束事件内容是一个结束事件, 包含cancelEventDefinition子元素
<endEvent id="myCancelEndEvent">
  <cancelEventDefinition />
</endEvent>

边界事件

  • 边界事件都是捕获事件,它会附在一个环节上
  • 边界事件是捕获事件,不可能触发事件:
    • 当节点运行时,事件会监听对应的触发类型
    • 当事件被捕获,节点就会中断,同时执行事件的后续连线
  • 边界事件的定义方式都一样:
<boundaryEvent id="myBoundaryEvent" attachedToRef="theActivity">
      <XXXEventDefinition/>
</boundaryEvent>
  • 边界事件使用如下方式进行定义:
    • 唯一标识:流程范围
    • 使用caught属性引用事件的节点,注意边界事件和它们附加的节点在同一级别上:比如,边界事件不是包含在节点内的
    • 格式为XXXEventDefinition的XML子元素 (比如,TimerEventDefinition,ErrorEventDefinition...)定义了边界事件的类型

定时边界事件

描述
  • 定时边界事件就是一个暂停等待警告的时钟
  • 当流程执行到绑定了边界事件的环节,会启动一个定时器
  • 当定时器触发时(一定时间之内),环节就会中断,并沿着定时边界事件的外出连线继续执行
图形标记
  • 定时边界事件是一个标准的边界事件(边界上的一个圆圈),内部是一个定时器小图标
    在这里插入图片描述
XML内容
  • 定时器边界任务定义是一个标准的边界事件,指定类型的子元素是timerEventDefinition元素
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
   <timerEventDefinition>
    <timeDuration>PT4H</timeDuration>
  </timerEventDefinition>
</boundaryEvent>
  • 在流程图中,圆圈边线是虚线:


    在这里插入图片描述
  • 经典应用场景: 发送通知邮件,但是不打断正常流程的执行
    • 中断和非中断的事件还是有区别的
      • 默认是中断事件
      • 非中断事件的情况,不会中断原始环节,那个环节还停留在原地
      • 对应的,会创建一个新分支,并沿着事件的流向继续执行.在XML内容中,要把cancelActivity属性设置为false
      <boundaryEvent id="escalationTimer" cancelActivity="false" attachedToRef="firstLineSupport"/>
      
  • ==注意:== 边界定时事件只能在job执行器启用时使用
    • 比如:把activiti.cfg.xml中的jobExecutorActivate设置为true,默认job执行器是禁用的
边界事件的问题
  • 同步问题: 边界事件后面不能有多条外出连线
  • 解决这个问题的方法是在一个连线后使用并发网关
    -

错误边界事件

描述
  • 错误边界事件: 节点边界上的中间捕获错误事件,会捕获节点范围内抛出的错误
  • 定义一个边界错误事件,大多用于内嵌子流程或者调用节点
    • 对于子流程的情况,它会为所有内部的节点创建一个作用范围
    • 错误是由错误结束事件抛出的.这个错误会传递给上层作用域,直到找到一个错误事件定义相匹配的边界错误事件
  • 当捕获了错误事件时 ,边界任务绑定的节点就会销毁,也会销毁内部所有的执行分支(同步节点,内嵌子流程...).流程执行会继续沿着边界事件的外出连线继续执行
图形标记
  • 错误边界事件显示成一个普通的中间事件(圆圈内部有一个小圆圈)放在节点的标记上,内部有一个错误小图标.错误小图标是白色的,表示它是一个捕获事件
    在这里插入图片描述
XML内容
  • 边界错误事件定义为普通的边界事件:
<boundaryEvent id="catchError" attachedToRef="mySubProcess">
  <errorEventDefinition errorRef="myError"/>
</boundaryEvent>
  • 和错误结束事件一样 ,errorRef引用了process元素外部的一个错误定义
<error id="myError" errorCode="123" />
...
<process id="myProcess">
...
  • errorCode用来匹配捕获的错误:
    • 如果没有设置errorRef,边界错误事件会捕获所有错误事件,无论错误的errorCode是什么
    • 如果设置了errorRef,并引用了一个已存在的错误,边界事件就只捕获错误代码与之相同的错误
    • 如果设置了errorRef,但是BPMN 2.0中没有定义错误,errorRef就会当做errorCode使用
错误边界事件实例
  • 如何使用错误结束事件的流程实例
    • 当完成审核盈利这个用户任务时,如果没有提供足够的信息,就会抛出错误
    • 错误会被子流程的边界任务捕获,所有回顾销售子流程中的所有节点都会销毁,即使审核客户比率还没有完成,并创建一个提供更多信息的用户任务


      在这里插入图片描述

信号边界事件

描述
  • 节点边界的中间捕获信号,会捕获信号定义引用的相同信号名的信号
  • 与其他事件(比如边界错误事件)不同,边界信号事件不只捕获绑定方位的信号.信号事件是一个全局的范围(广播语义),就是说信号可以在任何地方触发,即便是不同的流程实例
  • 和其他事件(比如边界错误事件)不同 ,捕获信号后,不会停止信号的传播. 如果有两个信号边界事件,捕获相同的信号事件,两个边界事件都会被触发,即使在不同的流程实例中
图形标记
  • 边界信号事件显示为普通的中间事件(圆圈里有个小圆圈),位置在节点的边缘, 内部有一个信号小图标.信号图标是白色的(未填充),表示捕获的意思
    在这里插入图片描述
XML内容
  • 边界信号事件定义为普通的边界事件:
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true">
          <signalEventDefinition signalRef="alertSignal"/>
</boundaryEvent>

消息边界事件

描述
  • 节点边界上的中间捕获消息, 根据引用的消息定义捕获相同消息名称的消息
图形标记
  • 边界消息事件显示成一个普通的中间事件(圆圈里有个小圆圈),位于节点边缘,内部是一个消息小图标.消息图标是白色(无填充),表示捕获的意思
    在这里插入图片描述
  • ==注意:== 边界消息事件可能是非中断(左侧) 或者中断(右侧)
XML内容
  • 边界消息事件定义为标准的边界事件
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true">
          <messageEventDefinition messageRef="newCustomerMessage"/>
</boundaryEvent>

取消边界事件

描述
  • 在事务性子流程的边界上的中间捕获取消
  • 事务取消时触发,当取消边界事件触发时:
    • 首先中断当前作用域的所有执行
    • 然后开始补偿事务内的所有激活的补偿边界事件.补偿是同步执行的:离开事务前,边界事务会等待补偿执行完毕
    • 当补偿完成后,事务子流程会沿着取消边界事务的外出连线继续执行
  • ==注意:==
    • 每个事务子流程只能有一个取消边界事件
    • 如果事务子流程包含内嵌子流程,补偿只会触发已经成功完成的子流程
    • 如果取消边界子流程对应的事务子流程配置为多实例,如果一个实例触发了取消,就会取消所有实例
图形标记
  • 取消边界事件显示为了一个普通的中间事件(圆圈里套小圆圈),在节点的边缘,内部是一个取消小图标.取消图标是白色(无填充),表明是捕获的意思


    在这里插入图片描述
XML内容
  • 取消边界事件定义为普通边界事件
<boundaryEvent id="boundary" attachedToRef="transaction" >
          <cancelEventDefinition />
</boundaryEvent>
  • 取消边界事件都是中断的,不需要使用cancelActivity属性

补偿边界事件

描述
  • 节点边界的中间捕获补偿
  • 用来设置一个节点的补偿处理器
  • 补偿边界事件必须使用直接引用设置唯一的补偿处理器
  • 补偿边界事件与其他边界事件的策略不同:
    • 其他边界事件(信号边界事件)当到达关联的节点就会被激活.离开节点时,就会挂起,对应的事件订阅也会取消
    • 补偿边界事件在关联的节点成功完成时激活,当补偿事件触发或对应流程实例结束时,事件订阅才会删除
  • 补偿边界事件遵循如下规则:
    • 补偿触发时,补偿边界事件对应的补偿处理器会调用相同次数,根据它对应的节点的成功次数
    • 如果补偿边界事件关联到多实例节点,补偿事件会订阅每个实例
    • 如果补偿边界事件关联的节点中包含循环,补偿事件会在每次节点执行时进行订阅
    • 如果流程实例结束,订阅的补偿事件都会结束
  • 补偿边界事件不支持内嵌子流程
图形标记
  • 补偿边界事件显示为标准中间事件(圆圈里套圆圈),位于节点边缘,内部有一个补偿小图标.补偿图标是白色的(无填充),表示捕获的意思
  • 下图演示使用无方向的关联,为边界事件设置补偿处理器:


    在这里插入图片描述
XML内容
  • 补偿边界事件定义为标准边界事件
<boundaryEvent id="compensateBookHotelEvt" attachedToRef="bookHotel" >
          <compensateEventDefinition />
</boundaryEvent>

<association associationDirection="One" id="a1"  sourceRef="compensateBookHotelEvt" targetRef="undoBookHotel" />

<serviceTask id="undoBookHotel" isForCompensation="true" activiti:class="..." />
  • 补偿边界事件在节点成功完成后激活, 不支持cancelActivity属性

中间捕获事件

  • 所有中间捕获事件都使用同样的方式定义:
<intermediateCatchEvent id="myIntermediateCatchEvent" >
      <XXXEventDefinition/>
</intermediateCatchEvent>
  • 中间捕获事件的定义:
    • 唯一标识(流程范围内)
    • 一个结构为XXXEventDefinition的XML子元素(TimerEventDefinition)定义了中间捕获事件的类型

定时中间捕获事件

描述
  • 定时中间事件作为一个监听器
  • 当执行到达捕获事件节点,就会启动一个定时器.当定时器触发(比如,一段时间之后),流程就会沿着定时中间事件的外出节点继续执行
图形标记
  • 定时器中间事件显示成标准中间捕获事件, 内部是一个定时器小图标:
    在这里插入图片描述
XML内容
  • 定时器中间事件定义为标准中间捕获事件. 指定类型的子元素为timerEventDefinition元素
        <intermediateCatchEvent id="timer">
            <timerEventDefinition>
                <timeDuration>PT5M</timeDuration>
            </timerEventDefinition>
        </intermediateCatchEvent>

信号中间捕获事件

  • 中间捕获信号事件,通过引用信号定义来捕获相同信号名称的信号
  • 信号中间捕获事件与其它事件(比如错误事件)不同:
    • 信号不会在捕获之后被消费
    • 如果有两个激活的信号边界事件捕获相同的信号事件,两个边界事件都会被触发,即便在不同的流程实例中

图形标记

  • 中间信号捕获事件显示为一个普通的中间事件(圆圈套圆圈),内部有一个信号小图标.信号小图标是白色的(无填充),表示捕获的意思
    在这里插入图片描述
XML内容
  • 信号中间事件定义为普通的中间捕获事件. 对应类型的子元素是signalEventDefinition元素
<intermediateCatchEvent id="signal">
        <signalEventDefinition signalRef="newCustomerSignal" />
</intermediateCatchEvent>

消息中间捕获事件

描述
  • 中间捕获消息事件,捕获特定名称的消息
图形标记
  • 中间捕获消息事件显示为普通中间事件(圆圈套圆圈),内部是一个消息小图标.消息图标是白色的(无填充),表示捕获的意思
    在这里插入图片描述
XML内容
  • 消息中间事件定义为标准中间捕获事件. 指定类型的子元素是messageEventDefinition元素
<intermediateCatchEvent id="message">
        <messageEventDefinition signalRef="newCustomerMessage" />
</intermediateCatchEvent>

内部触发事件

  • 所有内部触发事件的定义都是一样的:
<intermediateThrowEvent id="myIntermediateThrowEvent" >
      <XXXEventDefinition/>
</intermediateThrowEvent>
  • 内部触发事件定义包含:
    • 唯一标识(流程范围)
    • 使用格式为XXXEventDefinition的XML子元素(比如signalEventDefinition等)定义中间触发事件的类型
中间触发空事件
  • 空中间触发事件流程图,用于表示流程中的某个状态


    在这里插入图片描述
  • 可以添加执行监听器:
<intermediateThrowEvent id="noneEvent">
  <extensionElements>
    <activiti:executionListener class="org.activiti.engine.test.bpmn.event.IntermediateNoneEventTest$MyExecutionListener" event="start" />
  </extensionElements>
</intermediateThrowEvent>
  • 可以添加自己的代码,把事件发送给BAM工具或DWH.引擎不会为这个事件做任何事情,它直接径直通过

信号中间触发事件

描述
  • 信号中间触发事件为定义的信号抛出一个信号事件
  • 在activiti中,信号会广播到所有激活的处理器中.信号可以通过同步和异步方式发布
    • 默认配置下,信号是同步发送的:
      • 抛出事件的流程实例会等到信号发送给所有捕获流程实例才继续执行
      • 捕获流程实例也会在触发流程实例的同一个事务中执行
      • 如果某个监听流程出现了技术问题(抛出异常),所有相关的实例都会失败
    • 信号也可以异步发送:
      • 会在到达抛出信号事件后决定哪些处理器是激活的
      • 对这些激活的处理器,会保存一个异步提醒消息(任务),并发送给jobExecutor
图形标记
  • 中间信号触发事件显示为普通中间事件(圆圈套圆圈),内部又一个信号小图标,信号图标是黑色的(有填充),表示触发的意思
    在这里插入图片描述
XML内容
  • 消息中间事件定义为标准中间触发事件. 指定类型的子元素是signalEventDefinition元素
<intermediateThrowEvent id="signal">
        <signalEventDefinition signalRef="newCustomerSignal" />
</intermediateThrowEvent>
  • 异步信号事件如下:
<intermediateThrowEvent id="signal">
        <signalEventDefinition signalRef="newCustomerSignal" activiti:async="true" />
</intermediateThrowEvent>

补偿中间触发事件

描述
  • 用来触发补偿
  • 触发补偿:
    • 补偿可以由特定节点或包含补偿事件的作用域触发
    • 补偿是通过分配给节点的补偿处理器来完成的
      • 当补偿由节点触发,对应的补偿处理器会根据节点成功完成的次数执行相同次数
      • 如果补偿由当前作用域触发,当前作用域的所有节点都会执行补偿,也包含并发分支
      • 补偿的触发是继承式的:
        • 如果执行补偿的节点是子流程,补偿会作用到子流程中包含的所有节点
        • 如果子流程是内嵌节点,补偿会递归触发
        • 补偿不会传播到流程的上层
        • 如果补偿在子流程中触发,不会传播到子流程范围外
        • bpmn规范定义,由节点触发的流程只会作用到子流程同一级别
      • activiti的补偿执行次序与流程执行顺序相反: 最后完成的节点会最先执行补偿
      • 补偿中间触发事件可以用来补偿成功完成的事务性子流程
  • ==注意:==
    • 如果补偿被一个包含子流程的作用域触发,子流程还包含了关联补偿处理器的节点, 如果它已经成功完成了,补偿只会传播到子流程
    • 如果子流程中的节点也完成了,并关联了补偿处理器,如果子流程包含的这些节点还没有完成,就不会执行补偿处理器


      在这里插入图片描述

      这个流程中,我们有两个并发分支,一个分支是内嵌子流程,一个是使用信用卡节点.假设两个分支都启动了,第一个分支等待用户完成审核预定任务.第二个分支执行使用信用卡节点, 并发生了一个错误,这导致取消预定事件,并触发补偿.这时,并发子流程还没有结束,意味着补偿事件不会传播给子流程, 所以取消旅店预定这个补偿处理器不会执行.如果用户任务(就是内嵌子流程)在取消预定之前完成了,补偿就会传播给内嵌子流程

  • 流程变量:
    • 当补偿内嵌子流程时,用来执行补偿处理器的分支可以访问子流程的本地流程实例,因为这时是子流程完成的分支
    • 为了实现这个功能,流程变量的快照会分配给分支(为执行子流程而创建的分支)有以下限制条件:
      • 补偿处理器无法访问子流程内部创建的,添加到同步分支的变量
      • 分配给分支的流程变量在继承关系上层的(分配给流程实例的流程变量没有包含在快照中):补偿触发时,补偿处理器通过它们所在的地方访问这些流程变量
      • 变量快照只用于内嵌子流程,不适用其他节点
 已知限制:
 1. waitForCompletion="false"还不支持。当补偿使用中间触发补偿事件触发时, 事件没有等待,在补偿成功结束后
 2. 补偿自己由并发分支执行。并发分支的执行顺序与被补偿的节点完成次序相反。 未来activiti可能支持选项来顺序执行补偿
 3. 补偿不会传播给callActivity调用的子流程实例
图形标记
  • 中间补偿触发事件显示为标准中间事件(圆圈套圆圈),内部是一个补偿小图标.补偿图标是黑色的(有填充),表示触发的意思
    在这里插入图片描述
XML内容
  • 补偿中间事件定义为普通的中间触发事件. 对应类型的子元素是compensateEventDefinition元素
<intermediateThrowEvent id="throwCompensation">
        <compensateEventDefinition />
</intermediateThrowEvent>
  • 可选参数activityRef可以用来触发特定作用域/节点的补偿
<intermediateThrowEvent id="throwCompensation">
        <compensateEventDefinition activityRef="bookHotel" />
</intermediateThrowEvent>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容