边界事件
- 边界事件都是捕获事件,它会附在一个环节上
-
边界事件是捕获事件,不可能触发事件:
- 当节点运行时,事件会监听对应的触发类型
- 当事件被捕获,节点就会中断,同时执行事件的后续连线
- 边界事件的定义方式都一样:
<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>