结束事件
本文中内容和案例节选自贺波老师的《深入Activiti流程引擎:核心原理与高阶实战》一书。这本书中的内容更为全面、详尽,对系统学习和深入掌握Activiti/Flowable的用法非常有帮助,推荐给大家。
QQ交流群1:
633168411已满
QQ交流群2: 582010059
结束事件表示流程或分支的结束。结束事件总是抛出(Throwing)事件,这意味着当流程执行 到达结束事件时,会抛出一个结果。
在 Flowable 中,结束事件可以划分为以下几种类型:
- 空结束事件(None End Event)
- 错误结束事件(Error End Event)
- 取消结束事件(Cancel End Event)
- 终止结束事件(Terminate End Event) 结果的类型由事件内部的黑色图标描绘。在 XML 表示中,类型由子元素声明给出。
空结束事件
定义
空结束事件是最常见的一种结束事件,也是最简单的一种结束事件,只要把结束任务置于流程 或分支的最后节点,流程实例运行到该节点的时候,流程引擎就会结束该流程实例或分支。前面提 到,结束事件是抛出类型的,但空结束事件不处理抛出结果,我们可以理解为流程或分支正常结束 了,不需要执行其他的操作。 当流程实例有多个流程分支被激活时,只有当最后一个分支到达空结束事件正常结束后,流程 实例才结束。
图形标记
空结束事件是一个粗边圆圈,没有内部图标(无结果类型),如图所示:
XML内容
空结束事件的 XML 表示格式,为普通结束事件声明,没有任何子元素(其它种类的结束事件 都有子元素,用于声明其类型)。
<endEvent id = "endEvent1" name="noneEndEvent " ></endEvent>
错误结束事件
定义
错误结束事件会在流程到达错误结束事件的时候抛出错误,并结束当前的流程分支。异常结束 事件是有抛出结果的,它需要定义抛出错误码,如果找到了异常开始事件错误码,就会触发异常开 始事件。 错误结束事件只适用于子流程结束抛出错误事件,由父流程的错误边界事件捕获。
图形标记
错误结束事件是一个标准的结束事件(粗边圆圈),内部有错误图标。错误图标是全黑的,表 示触发语法,如图所示
XML内容
错误结束事件,表示为结束事件,加上 errorEventDefinition 子元素,errorRef 属性可以引用在 流程外定义的 error 元素:
<error id="theError" />
<process id="errorEndEventProcess">
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="theError" />
</endEvent>
</process>
在以上 xml 代码片段中,首先定义了一个 id 属性值为 theError 的错误,然后在结束事件中使 用 errorEventDefinition 元素引用该 error,从而构成了一个错误结束事件。
界面操作
演示demo
使用示例
错误结束事件一般和错误边界事件(Intermediate Boundary Error Event)搭配一起使用,错误 结束事件触发错误边界事件,错误边界事件捕获错误结束事件抛出的错误信息,通常在嵌套子流程 和调用子流程中使用。如果找不到匹配的错误边界事件,将会抛出异常。 用户启动流程,下单之后进入付款子流程,如果付款成功,子流程到达空结束事件从而子流程 结束,进入后续的发货节点;如果付款失败,到达错误结束事件,抛出错误并结束子流程,子流程 上的错误边界事件捕获到错误信息,重新启动付款子流程。对应的流程图如图所示:
<error id="payError" errorCode="payErrorCode" />
<process id="ErrorEndEventProcess" name="错误结束事件" isExecutable="true">
<userTask id="a9485eda61d534bd5a6bf059c359637cf" name="下单">
<extensionElements>
<flowable:formData />
<flowable:assigneeType>static</flowable:assigneeType>
</extensionElements>
</userTask>
<sequenceFlow id="aaeb88fef071f4fa88aea70b5ce4cefd5" sourceRef="ac0a8178a92164c37b8be22cc6023b8aa" targetRef="a9485eda61d534bd5a6bf059c359637cf" />
<sequenceFlow id="Flow_01p5dv8" sourceRef="a9485eda61d534bd5a6bf059c359637cf" targetRef="Activity_0vse4d1" />
<subProcess id="Activity_0vse4d1" name="付款子流程">
<extensionElements>
<flowable:assigneeType>static</flowable:assigneeType>
<flowable:formData />
</extensionElements>
<startEvent id="Event_1u7pw9m">
<extensionElements>
<flowable:formData />
</extensionElements>
</startEvent>
<userTask id="Activity_08d9gg7" name="付款">
<extensionElements>
<flowable:assigneeType>static</flowable:assigneeType>
<flowable:formData />
</extensionElements>
</userTask>
<sequenceFlow id="Flow_07eodwu" sourceRef="Event_1u7pw9m" targetRef="Activity_08d9gg7" />
<exclusiveGateway id="Gateway_1e8ts1f" />
<sequenceFlow id="Flow_0bzye5t" sourceRef="Activity_08d9gg7" targetRef="Gateway_1e8ts1f" />
<endEvent id="Event_1v4gxpv" />
<sequenceFlow id="Flow_0on37gt" name="支付成功" sourceRef="Gateway_1e8ts1f" targetRef="Event_1v4gxpv">
<conditionExpression xsi:type="tFormalExpression">${payResult == true}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_0dqc8u3" name="支付失败" sourceRef="Gateway_1e8ts1f" targetRef="Event_1w3dv09">
<conditionExpression xsi:type="tFormalExpression">${payResult == false}</conditionExpression>
</sequenceFlow>
<endEvent id="Event_1w3dv09">
<errorEventDefinition errorRef="payError" flowable:errorVariableLocalScope="false" flowable:errorVariableTransient="false" />
</endEvent>
</subProcess>
<userTask id="Activity_062xb68" name="发货">
<extensionElements>
<flowable:assigneeType>static</flowable:assigneeType>
<flowable:formData />
</extensionElements>
</userTask>
<sequenceFlow id="Flow_0spxrt9" sourceRef="Activity_0vse4d1" targetRef="Activity_062xb68" />
<userTask id="Activity_067yadn" name="收货" />
<sequenceFlow id="Flow_0y2xpmk" sourceRef="Activity_062xb68" targetRef="Activity_067yadn" />
<endEvent id="Event_0b3nzse" />
<sequenceFlow id="Flow_1aiwj8e" sourceRef="Activity_067yadn" targetRef="Event_0b3nzse" />
<boundaryEvent id="Event_00bbo9x" attachedToRef="Activity_0vse4d1">
<errorEventDefinition errorRef="payError" flowable:errorVariableLocalScope="false" flowable:errorVariableTransient="false" />
</boundaryEvent>
<sequenceFlow id="Flow_14f59h2" name="重新付款" sourceRef="Event_00bbo9x" targetRef="Activity_0vse4d1" />
<startEvent id="ac0a8178a92164c37b8be22cc6023b8aa">
<extensionElements>
<flowable:formData />
</extensionElements>
</startEvent>
</process>
取消结束事件
定义
取消结束事件只能与 BPMN 事务子流程结合使用,它可以取消一个事务子流程的执行,同时 也只能在子流程中执行。实际应用中,会把取消事件,事务子流程,补偿事件一起用。当到达取消 结束事件时,会抛出取消事件,它必须被取消边界事件捕获。取消边界事件会取消事务,并触发补 偿机制。
图形标记
取消结束事件显示为标准的结束事件(粗边圆圈),包含一个取消图标。取消图标是全黑的, 表示触发语法,如图所示:
XML内容
取消结束事件内容是一个结束事件,包含 cancelEventDefinition 子元素:
<process id="cancelEndEventProcess">
<endEvent id="cancelEndEvent">
<cancelEventDefinition/>
</endEvent>
</process>
使用示例
取消结束事件,只能与事务子流程(Transaction Subprocess)一起使用。当到达取消结束事件 时,会抛出取消事件,且必须由取消边界事件(Cancel Boundary Event)捕获。之后这个取消边界 事件将取消事务,并触发补偿(compensation)。 下面我们看一个使用取消结束事件的示例流程,如图所示是一个系统上线流程,流程启 动后进入系统上线事务子流程,首先到达“人工上线”用户任务节点,办理完成后到达取消结束事 件,抛出取消事件,触发“自动回滚”补偿,并触发取消边界事件以及结束子流程进而流转到“用 户排查”用户任务节点。这个示例流程中涉及到用户任务节点、服务任务节点、事务子流程和取消 边界事件,这些都是 BPMN 定义的流程元素,在后面的章节中会展开介绍。
<error id="errorFlag" errorCode="500" />
<process id="ThransactionSubProcessTest" name="子流程-事务子流程" isExecutable="true">
<startEvent id="a1bc9933739624c6694151aff2dce872b" />
<userTask id="aa49686c18f1c48879976ba75a55fcbc6" name="用户提交订单">
<extensionElements>
<flowable:formData />
<flowable:assigneeType>static</flowable:assigneeType>
</extensionElements>
</userTask>
<sequenceFlow id="ab3c3111802e74e1c829879ce06ef62f1" sourceRef="a1bc9933739624c6694151aff2dce872b" targetRef="aa49686c18f1c48879976ba75a55fcbc6" />
<transaction id="Activity_1vnyjkd" name="事务子流程">
<startEvent id="Event_12nf6w8">
<extensionElements>
<flowable:formData />
</extensionElements>
</startEvent>
<sequenceFlow id="Flow_1qdwcnq" sourceRef="Event_12nf6w8" targetRef="Gateway_1swfvxl" />
<parallelGateway id="Gateway_1swfvxl" />
<sequenceFlow id="Flow_17rtq7v" sourceRef="Gateway_1swfvxl" targetRef="Activity_1gw2yen" />
<serviceTask id="Activity_1gw2yen" name="锁定库存" flowable:class="com.dragon.test.bpmn.delegate.TreasuryLockService">
<extensionElements>
<flowable:formData />
<flowable:assigneeType>static</flowable:assigneeType>
</extensionElements>
</serviceTask>
<userTask id="Activity_0s32nn4" name="用户取消订单">
<extensionElements>
<flowable:formData />
<flowable:assigneeType>static</flowable:assigneeType>
</extensionElements>
</userTask>
<sequenceFlow id="Flow_0x4x7li" sourceRef="Gateway_1swfvxl" targetRef="Activity_0s32nn4" />
<userTask id="Activity_0k0ojol" name="用户支付订单">
<extensionElements>
<flowable:formData />
<flowable:assigneeType>static</flowable:assigneeType>
</extensionElements>
</userTask>
<sequenceFlow id="Flow_107046y" sourceRef="Activity_1gw2yen" targetRef="Activity_0k0ojol" />
<sequenceFlow id="Flow_1yuazgn" sourceRef="Activity_0k0ojol" targetRef="Activity_0bi67sc" />
<serviceTask id="Activity_0bi67sc" name="扣减库存" flowable:class="com.dragon.test.bpmn.delegate.TreasuryDeductService">
<extensionElements>
<flowable:assigneeType>static</flowable:assigneeType>
<flowable:formData />
</extensionElements>
</serviceTask>
<endEvent id="Event_167temk" />
<sequenceFlow id="Flow_0pkp6lj" sourceRef="Activity_0bi67sc" targetRef="Event_167temk" />
<endEvent id="Event_1mt0jp2">
<cancelEventDefinition />
</endEvent>
<boundaryEvent id="Event_1w62z13" attachedToRef="Activity_0bi67sc">
<errorEventDefinition errorRef="errorFlag" flowable:errorVariableLocalScope="false" flowable:errorVariableTransient="false" />
</boundaryEvent>
<boundaryEvent id="Event_0fblty6" name="30分钟" attachedToRef="Activity_0k0ojol">
<timerEventDefinition>
<timeDuration>PT3M</timeDuration>
</timerEventDefinition>
</boundaryEvent>
<boundaryEvent id="Event_0dzq6vl" attachedToRef="Activity_1gw2yen">
<compensateEventDefinition />
</boundaryEvent>
<serviceTask id="Activity_15oy2bt" name="释放库存" isForCompensation="true" flowable:class="com.dragon.test.bpmn.delegate.TreasuryReleaseService" />
<boundaryEvent id="Event_0rv7u1v" attachedToRef="Activity_0k0ojol">
<compensateEventDefinition />
</boundaryEvent>
<serviceTask id="Activity_0gw5xlk" name="费用退回" isForCompensation="true" flowable:class="com.dragon.test.bpmn.delegate.RefundPaymentService" />
<association id="Association_1a1b669" associationDirection="One" sourceRef="Event_0dzq6vl" targetRef="Activity_15oy2bt" />
<association id="Association_0vig570" associationDirection="One" sourceRef="Event_0rv7u1v" targetRef="Activity_0gw5xlk" />
</transaction>
<sequenceFlow id="Flow_0ynhbof" sourceRef="aa49686c18f1c48879976ba75a55fcbc6" targetRef="Activity_1vnyjkd" />
<boundaryEvent id="Event_0lxd35r" attachedToRef="Activity_1vnyjkd">
<cancelEventDefinition />
</boundaryEvent>
<sequenceFlow id="Flow_0p83e5j" sourceRef="Event_0lxd35r" targetRef="Activity_0xmvtli" />
<serviceTask id="Activity_0xmvtli" name="自动取消订单" flowable:class="com.dragon.test.bpmn.delegate.CancelOrderService">
<extensionElements>
<flowable:formData />
<flowable:assigneeType>static</flowable:assigneeType>
</extensionElements>
</serviceTask>
<endEvent id="Event_0h8me6c" />
<sequenceFlow id="Flow_1vvt0is" sourceRef="Activity_0xmvtli" targetRef="Event_0h8me6c" />
<endEvent id="Event_1954lc4" />
<sequenceFlow id="Flow_0kcxljy" sourceRef="Activity_1vnyjkd" targetRef="Event_1954lc4" />
</process>
注意
⑴取消结束事件只能使用在事务子流程中
⑵取消结束事件会触发依附在子流程上的取消边界事件(取消结束事件会被抛出,而取消边界 事件则会捕获事件)
⑶在 BPMN2.0 中对于已经完成的活动,可以使用补偿机制,而对于一些正在进行的活动,不 能使用补偿机制,而使用取消机制。取消事件一定要包含补偿事件,否则无法运行,会抛出 org.flowable.common.engine.api.FlowableException: No execution found for sub process of boundary cancel event ***的 异常
演示demo
终止结束事件
定义
当流程到达终止结束事件时,该流程将终止。当流程实例有多个流程分支被激活时,当有一个 分支到达终止结束事件时,所有其它流程分支也立即结束。在 flowable 中,当流程执行到达终止结 束事件时,会判断第一个范围 scope(流程或子流程)并终止它。终止结束事件对嵌入式子流程, 调用活动,事件子流程,或事务子流程都有效。
图形标记
终止结束事件显示为标准的结束事件(粗边圆圈),包含一个黑色实心圆图标,如图所 示:
XML内容
终止结束事件,表示为结束事件,加上 terminateEventDefinition 子元素,格式为:
<endEvent id="Event_1d7iay7">
<terminateEventDefinition flowable:terminateAll="true" />
</endEvent>
注意
terminateAll 属性是可选的,默认为 false。当存在多实例的调用过程或嵌入式 子流程时,如果 terminateAll 属性为默认值 false 时,只会终止其一个实例,而其他的实例与流程实 例不会受影响。如果 terminateAll 属性设置为 true,无论该终止结束事件在流程定义中任何位置, 也无论它是否在子流程(甚至是嵌套子流程)中,都会终止(根)流程实例。