取消事件(Cancel Events):
一、取消結(jié)束事件(Cancel End Event):
?????? 取消結(jié)束事件只能與事務(wù)子流程配合使用。當(dāng)流程到達(dá)取消結(jié)束事件,一個(gè)取消事件將會(huì)被拋出约素,這個(gè)取消事件必須被一個(gè)取消邊界事件捕獲。這取消邊界事件隨后會(huì)取消這個(gè)事務(wù)并觸發(fā)補(bǔ)償秩仆。
二、取消邊界事件(Cancel Boundary Event):
?????? 依附于事務(wù)子流程的上的中間捕獲取消邊界事件猾封,或者簡(jiǎn)稱(chēng)取消邊界事件澄耍。當(dāng)一個(gè)事務(wù)被取消時(shí),取消邊界事件將會(huì)被觸發(fā)晌缘。當(dāng)取消邊界事件被觸發(fā)后齐莲,它首先打斷在這個(gè)作用域下的所有活動(dòng)的執(zhí)行。接下來(lái)磷箕,它會(huì)開(kāi)始執(zhí)行補(bǔ)償所有在這個(gè)事務(wù)的作用域內(nèi)的活動(dòng)的補(bǔ)償邊界事件选酗。補(bǔ)償行為是同步的,就是說(shuō)邊界事件會(huì)一直等待到補(bǔ)償事件完成后才會(huì)離開(kāi)事務(wù)岳枷。即當(dāng)補(bǔ)償完成后芒填,這個(gè)事務(wù)子流程會(huì)離開(kāi)取消邊界事件。
注意:
?????? 1.一個(gè)事務(wù)子流程只允許有一個(gè)取消邊界事件
?????? 2.如果事務(wù)子流程有嵌套的子流程空繁,只有那些子流程已經(jīng)完全成功的子流程才會(huì)觸發(fā)補(bǔ)償
?????? 3.如果取消邊界事件放置在多個(gè)流程實(shí)例的事務(wù)子流程上殿衰,如果一個(gè)實(shí)例觸發(fā)取消,所有的實(shí)例都會(huì)取消盛泡。
?????? 一個(gè)典型的邊界事件的定義:
<boundaryEvent id="boundary" attachedToRef="transaction" >
<cancelEventDefinition />
</boundaryEvent>
?????? 因?yàn)槿∠吔缡录偸强芍袛嗟拿葡椋圆恍枰猚ancelActivity屬性
補(bǔ)償事件(Compensation Events):
一、中間拋出補(bǔ)償事件(Intermediate Throwing Compensation Event):
?????? 中間拋出補(bǔ)償事件用于觸發(fā)一個(gè)補(bǔ)償:
觸發(fā)補(bǔ)償:補(bǔ)償事件可以被指定的活動(dòng)觸發(fā)傲诵,或者一個(gè)擁有補(bǔ)償事件的作用域觸發(fā)凯砍。補(bǔ)償?shù)膱?zhí)行是通過(guò)一個(gè)活動(dòng)的補(bǔ)償handler的execution來(lái)執(zhí)行補(bǔ)償
?????? 1.當(dāng)為某個(gè)活動(dòng)拋出一個(gè)補(bǔ)償時(shí),相關(guān)的補(bǔ)償handler執(zhí)行的次數(shù)與活動(dòng)完成的次數(shù)相同拴竹。
?????? 2.如果是在當(dāng)前作用域拋出的補(bǔ)償悟衩,則當(dāng)前作用域的所有活動(dòng)都將要被補(bǔ)償,包括并發(fā)分支上的活動(dòng)栓拜。
?????? 3.補(bǔ)償事件會(huì)被有層次的觸發(fā):如果被補(bǔ)償?shù)幕顒?dòng)時(shí)一個(gè)子流程座泳,所有包含在這個(gè)子流程內(nèi)的活動(dòng)都會(huì)被觸發(fā)補(bǔ)償斑响。如果這個(gè)子流程有嵌套的活動(dòng),補(bǔ)償事件會(huì)遞歸的向下拋出钳榨。但是補(bǔ)償事件不會(huì)廣播到比這個(gè)流程高的層級(jí)。如果一個(gè)補(bǔ)償在一個(gè)子流程內(nèi)觸發(fā)纽门,它不會(huì)廣播到這個(gè)子流程的作用域外的活動(dòng)上去薛耻。BPMN規(guī)范規(guī)定對(duì)“同一級(jí)別的子流程”上的活動(dòng)觸發(fā)補(bǔ)償。
?????? 4.補(bǔ)償被補(bǔ)償事件子流程(compensation event subprocess)消費(fèi)赏陵,如果一個(gè)被補(bǔ)償?shù)幕顒?dòng)是一個(gè)子流程饼齿,并且這個(gè)子流程包含一個(gè)補(bǔ)償事件子流程,且這個(gè)流程被補(bǔ)償開(kāi)始事件觸發(fā)蝙搔,那么補(bǔ)償觸發(fā)的是這個(gè)補(bǔ)償事件子流程而不是觸發(fā)這個(gè)活動(dòng)包含的子流程缕溉。
?????? 5.補(bǔ)償是以相反的順序執(zhí)行的,這意味著最后完成的活動(dòng)吃型,最先獲得補(bǔ)償证鸥。
?????? 6.中間拋出補(bǔ)償事件可以用來(lái)補(bǔ)償已經(jīng)完成的事物子流程
注意:如果補(bǔ)償在一個(gè)作用域內(nèi)被拋出,這個(gè)作用域包含一個(gè)子流程并且這個(gè)子流程包含一個(gè)帶有補(bǔ)償handler的活動(dòng)勤晚,只有當(dāng)子流程完成時(shí)枉层,并且補(bǔ)償被拋出,補(bǔ)償才會(huì)傳播到子流程的補(bǔ)償handler赐写。如果嵌套在子流程中的某些活動(dòng)已完成并有附加補(bǔ)償處理程序鸟蜡,則如果包含這些活動(dòng)的子流程尚未完成,則補(bǔ)償行為不會(huì)被執(zhí)行挺邀。 考慮以下示例:
?????? 在圖示的流程中揉忘,有兩個(gè)并發(fā)的執(zhí)行,一個(gè)執(zhí)行被包含的子流程端铛,一個(gè)執(zhí)行信用卡充值活動(dòng)泣矛。我們假設(shè)兩個(gè)執(zhí)行都已經(jīng)開(kāi)始了,并且第一個(gè)第一個(gè)執(zhí)行正在等待一個(gè)用戶去完成檢查預(yù)定任務(wù)沦补。第二個(gè)執(zhí)行正在執(zhí)行信用卡充值的活動(dòng)并且一個(gè)錯(cuò)誤被拋出乳蓄,這個(gè)錯(cuò)誤會(huì)導(dǎo)致取消補(bǔ)償事件觸發(fā)補(bǔ)償。在這時(shí)這個(gè)并行的子流程還沒(méi)完成夕膀,這意味著這個(gè)補(bǔ)償事件沒(méi)有傳播到這個(gè)子流程虚倒,因此 取消酒店預(yù)定補(bǔ)償handler沒(méi)有執(zhí)行。如果這個(gè)檢查預(yù)定活動(dòng)在取消預(yù)定拋出事件之前被執(zhí)行产舞,補(bǔ)償事件會(huì)傳播到這個(gè)被包含的子流程里魂奥。
注意:多實(shí)例活動(dòng)拋出補(bǔ)償時(shí),只有當(dāng)所有的流程實(shí)例都結(jié)束了相關(guān)的補(bǔ)償handler才會(huì)執(zhí)行易猫。這意味著多實(shí)例活動(dòng)在被補(bǔ)償前必須先被結(jié)束掉耻煤。
流程變量:在補(bǔ)償一個(gè)被包含的子流程時(shí),用于執(zhí)行補(bǔ)償?shù)膆andler可以訪問(wèn)子流程完成后,子流程的本地流程變量(local process variables)哈蝇。為此棺妓,子流程作用域內(nèi)的流程變量將被作為快照保存起來(lái)。
由此炮赦,我們可以得出一些推論:
?????? 1.補(bǔ)償handler不會(huì)去訪問(wèn)當(dāng)前執(zhí)行中的子流程中的流程變量
?????? 2.快照里不包含與更高層執(zhí)行相關(guān)的流程變量怜跑,例如與流程實(shí)例執(zhí)行相關(guān)的流程變量:補(bǔ)償handler可以在補(bǔ)償被拋出時(shí)的狀態(tài)下去訪問(wèn)這些流程變量
?????? 3.變量快照只在被包含的子流程中被采用,其他活動(dòng)不被支持
當(dāng)前的一些限制:
?????? 1.waitForCompletion="false"在補(bǔ)償事件中是不被支持的吠勘,當(dāng)用中間拋出補(bǔ)償事件(intermediate throwing compensation)觸發(fā)補(bǔ)償時(shí)性芬,在補(bǔ)償完成后只剩下這個(gè)事件(the event is only left after compensation completed successfully)
?????? 2.補(bǔ)償本身是被并發(fā)執(zhí)行的,這個(gè)并發(fā)執(zhí)行的順序與被不補(bǔ)償活動(dòng)完成的順序相反剧防,之后的版本可能會(huì)包含一個(gè)可選的補(bǔ)償執(zhí)行順序植锉。
?????? 3.補(bǔ)償不會(huì)廣播到由調(diào)用活動(dòng)產(chǎn)生子流程中去(懵逼臉)
定義一個(gè)中間補(bǔ)償拋出事件:
?????? 補(bǔ)償中間事件被定義為一個(gè)中間拋出事件,在這個(gè)例子中特定類(lèi)型的子元素是compensateEventDefinition元素:
<intermediateThrowEvent id="throwCompensation">
<compensateEventDefinition />
</intermediateThrowEvent>
?????? 另外峭拘,可選參數(shù)activityRef可以觸發(fā)一個(gè)特定活動(dòng)或者作用域的補(bǔ)償:
<intermediateThrowEvent id="throwCompensation">
<compensateEventDefinition activityRef="bookHotel" />
</intermediateThrowEvent>
二俊庇、補(bǔ)償結(jié)束事件(Compensation End Event):
?????? 補(bǔ)償結(jié)束事件觸發(fā)補(bǔ)償,并且結(jié)束當(dāng)前執(zhí)行路徑鸡挠。它與補(bǔ)償中間拋出事件具有相同的行為和限制暇赤。
<endEvent id="throwCompensation">
<compensateEventDefinition />
</endEvent>
三、補(bǔ)償邊界事件(Compensation Boundary Event):
?????? 依附于一個(gè)活動(dòng)的邊界上的中間捕獲補(bǔ)償事件宵凌。簡(jiǎn)稱(chēng)補(bǔ)償邊界事件鞋囊。用作附著一個(gè)補(bǔ)償handler到一個(gè)活動(dòng)或者一個(gè)被包含的子流程上。
?????? 補(bǔ)償邊界事件必須直接引用一個(gè)相關(guān)的補(bǔ)償handler瞎惫。
?????? 與其他邊界事件相比溜腐,補(bǔ)償邊界事件有不同的行為策略。其他的邊界事件瓜喇,例如信號(hào)邊界事件挺益,當(dāng)活動(dòng)到達(dá)時(shí),信號(hào)邊界事件就開(kāi)始了乘寒,當(dāng)活動(dòng)結(jié)束望众,它也就結(jié)束了,并且相關(guān)的事件訂閱也被取消伞辛。補(bǔ)償邊界事件不同烂翰,補(bǔ)償邊界事件只有當(dāng)被依附的活動(dòng)完全結(jié)束后,才會(huì)被激活蚤氏。與此同時(shí)甘耿,相關(guān)的邊界事件訂閱被創(chuàng)建。當(dāng)邊界事件被觸發(fā)或者相關(guān)的流程實(shí)例結(jié)束竿滨,這個(gè)訂閱也會(huì)被刪除佳恬。
這就引出了下面的幾點(diǎn):
?????? 1.當(dāng)補(bǔ)償被觸發(fā)時(shí)捏境,被補(bǔ)償邊界事件依附的活動(dòng)完成的同時(shí),這個(gè)與補(bǔ)償邊界事件關(guān)聯(lián)的補(bǔ)償handler被調(diào)用毁葱。
?????? 2.如果一個(gè)補(bǔ)償事件依附了一個(gè)多實(shí)例活動(dòng)垫言,那么會(huì)為每一個(gè)補(bǔ)償事件創(chuàng)建一個(gè)訂閱。
?????? 3.如果補(bǔ)償邊界事件依附于一個(gè)活動(dòng)倾剿,且這個(gè)活動(dòng)被包含在一個(gè)循環(huán)中骏掀。則每次這個(gè)活動(dòng)被執(zhí)行時(shí),都會(huì)給它創(chuàng)建一個(gè)補(bǔ)償事件訂閱柱告。
?????? 4.如果流程實(shí)例結(jié)束,那么補(bǔ)償事件訂閱也就將被取消掉笑陈。
定義一個(gè)補(bǔ)償邊界事件:
<boundaryEvent id="compensateBookHotelEvt" attachedToRef="bookHotel" >
<compensateEventDefinition />
</boundaryEvent>
<association associationDirection="One" id="a1" sourceRef="compensateBookHotelEvt" targetRef="undoBookHotel" />
<serviceTask id="undoBookHotel" isForCompensation="true" camunda:class="..." />
?????? 因?yàn)檠a(bǔ)償邊界事件是在活動(dòng)完全結(jié)束后才被激活的际度,所以cancelActivity屬性是不被支持的。
四涵妥、補(bǔ)償開(kāi)始事件(Compensation Start Event):
?????? 補(bǔ)償開(kāi)始事件只被用作觸發(fā)一個(gè)事件子流程乖菱,它不可以被用作發(fā)起一個(gè)流程實(shí)例。這種類(lèi)型的子流程被稱(chēng)作補(bǔ)償事件子流程蓬网。
?????? 補(bǔ)償事件子流程可以被用作一個(gè)被子流程包含的補(bǔ)償handler实辑。類(lèi)似補(bǔ)償邊界事件依附一個(gè)子流程捺氢,補(bǔ)償事件子流程也只有在補(bǔ)償事件被拋出時(shí)才會(huì)被調(diào)用。在子流程完成之前剪撬,補(bǔ)償事件子流程將會(huì)被調(diào)用跟子流程完成的次數(shù)相同的次數(shù)摄乒,在下面這個(gè)例子中:部署一個(gè)補(bǔ)償事件子流程的流程定義時(shí)窒所,需要注意一下幾點(diǎn):
?????? 1.補(bǔ)償事件子流程只支持被包含的子流程,不是流程級(jí)別的帆锋。因?yàn)檫@個(gè)限制吵取,補(bǔ)償不會(huì)傳播到由調(diào)用活動(dòng)產(chǎn)生的子流程實(shí)例。
?????? 2.在同一層級(jí)的子流程只允許有一個(gè)補(bǔ)償事件子流程
?????? 3.帶有補(bǔ)償事件子流程的子流程不支持被一個(gè)補(bǔ)償邊界事件依賴(lài)锯厢,因?yàn)檠a(bǔ)償事件子流程和補(bǔ)償邊界事件有相同的意圖皮官,所以他們只能有一個(gè)被選用。
?????? 上面的流程中包含一個(gè)被包含的補(bǔ)償事件子流程,這個(gè)補(bǔ)償事件子流程將會(huì)被補(bǔ)償開(kāi)始事件觸發(fā)残黑。注意馍佑,這個(gè)補(bǔ)償handler與默認(rèn)的補(bǔ)償handler不一樣,因?yàn)樗怯靡粋€(gè)特定的獨(dú)立于execution指令去觸發(fā)補(bǔ)償活動(dòng)梨水。它也包含一個(gè)附加流程活動(dòng)挤茄,這個(gè)附加邏輯無(wú)法從子流程自身派生出來(lái)。
定義一個(gè)補(bǔ)償開(kāi)始事件:
?????? 下面這個(gè)xml表示一個(gè)補(bǔ)償開(kāi)始事件是一個(gè)帶有compensateEventDefinition子元素的普通開(kāi)始事件:
<subProcess id="compensationEventSubprocess" triggeredByEvent="true">
<startEvent id="compensationStart" >
<compensateEventDefinition />
</startEvent>
<!-- ... -->
</subProcess>