camunda-bpmn-條件事件(Conditional Events)

?????? 條件事件定義了一個(gè)給定條件解析為true時(shí)就觸發(fā)的事件。它可以被用作事件子流程的開(kāi)始事件,也可以用作中間事件和邊界事件。條件開(kāi)始事件和條件邊界事件可以是可中斷和不可中斷的。

?????? 在camunda中,條件事件可以在流程變量的幫助下觸發(fā),在下面的圖中,所有的條件事件都被使用了:

圖1:條件事件

?????? 正如你所見(jiàn),一個(gè)中間條件事件就像是一個(gè)等待,會(huì)一直等到條件被滿足。在這個(gè)例子中,如果這個(gè)處理器變成可用,且這個(gè)條件是true,例如: ${processorAvailable == true},這時(shí)條件會(huì)被滿足,流程會(huì)執(zhí)行到下一個(gè)活動(dòng)。
?????? 如果條件邊界事件的條件檢測(cè)到申請(qǐng)被改變了,接著相關(guān)的檢查申請(qǐng)會(huì)被中斷。
?????? 在整個(gè)流程的執(zhí)行過(guò)程中,這個(gè)申請(qǐng)是可以被取消的。如果條件開(kāi)始事件滿足條件(申請(qǐng)被取消),這個(gè)流程實(shí)例的執(zhí)行會(huì)被這個(gè)事件子流程中斷,這會(huì)取消這個(gè)申請(qǐng)的當(dāng)前流程。

一、條件(Condition):

?????? 為了指明一個(gè)條件事件何時(shí)應(yīng)該被觸發(fā),conditionalEventDefinition元素必須要指定一個(gè)condition子元素。

<conditionalEventDefinition>
  <condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>

?????? 這個(gè)指定的條件是支持EL表達(dá)式的,并且可以訪問(wèn)流程實(shí)例變量。每次流程變量發(fā)生改變時(shí),都會(huì)重新計(jì)算一次條件表達(dá)式。
?????? 為了防止所有流程變量改變都對(duì)條件進(jìn)行計(jì)算,這個(gè)計(jì)算可以被限制到特定的變量的改變。為此,可以使用擴(kuò)展屬性camunda:variableName和camunda:variableEvents
?????? 默認(rèn)情況下,條件計(jì)算會(huì)被任何變量的改變而觸發(fā),不管是創(chuàng)建更新和刪除(create/update/delete)任何變量。variableName可以被用作限制指定的變量的改變。variableEvents可以限制改變的類(lèi)型。可以指定多個(gè)變量的改變,用逗號(hào)隔開(kāi)。這些屬性可以混合使用。
?????? conditionalEventDefinition可以被定義成下面的例子的樣子:

<conditionalEventDefinition camunda:variableName="var1" camunda:variableEvents="create, update">
  <condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>

?????? 上面的條件只有在var1變量在被創(chuàng)建或者被更新的時(shí)候才會(huì)被執(zhí)行。這個(gè)屬性對(duì)于不可中斷的事件很有用。因?yàn)檫@些事件可以被多次觸發(fā)。

二、條件邊界事件(Conditional Boundary Event):

?????? 條件邊界事件就像一個(gè)監(jiān)視器一樣,監(jiān)視指定的條件是否滿足,然后被觸發(fā)。
?????? 中斷和不可中斷條件事件是有區(qū)別的,默認(rèn)是可中斷事件。不可中斷事件會(huì)導(dǎo)致原始的活動(dòng)不能被中斷。這個(gè)實(shí)例會(huì)保持在活動(dòng)的狀態(tài)。并且會(huì)創(chuàng)建一個(gè)額外的執(zhí)行路徑,taking the outgoing transition of the event。一個(gè)不可中斷條件事件可以被觸發(fā)多次,只要這個(gè)被依附的活動(dòng)時(shí)活動(dòng)的。
?????? 下面這個(gè)xml代表一個(gè)不可中斷條件事件,cancelActivity屬性被設(shè)置為false:

<boundaryEvent id="conditionalEvent" attachedToRef="taskWithCondition" cancelActivity="false">
  <conditionalEventDefinition>
    <condition type="tFormalExpression">${var1 == 1}</condition>
  </conditionalEventDefinition>
</boundaryEvent>

三、中間條件捕獲事件(Intermediate Conditional Catch Event):

?????? 中間條件事件就像一個(gè)等待,直到條件為true。當(dāng)流程執(zhí)行到捕獲事件時(shí),這個(gè)條件會(huì)首先被計(jì)算。如果滿足條件,流程會(huì)執(zhí)行到下一個(gè)活動(dòng)。如果條件不滿足,流程執(zhí)行會(huì)停留在這個(gè)活動(dòng)上,直到條件滿足。
?????? 中間條件事件被定義成一個(gè)捕獲事件。指定的子元素是conditionalEventDefinition:

<intermediateCatchEvent id="conditionalEvent">
  <conditionalEventDefinition>
    <condition type="tFormalExpression">${var1 == 1}</condition>
  </conditionalEventDefinition>
</intermediateCatchEvent>

四、條件開(kāi)始事件(Conditional Start Event):

?????? 條件開(kāi)始實(shí)際可以被用作通過(guò)計(jì)算某些條件來(lái)發(fā)起一個(gè)流程,一個(gè)流程可以有一個(gè)或者多個(gè)條件開(kāi)始事件。
?????? 如果多個(gè)條件滿足,則會(huì)發(fā)起響應(yīng)數(shù)量的流程實(shí)例。

當(dāng)部署一個(gè)條件開(kāi)始流程定義時(shí),我們需要考慮一下事項(xiàng):
?????? 1.給定流程定義的條件開(kāi)始事件的條件必須是唯一的,即一個(gè)流程定義中不允許有多個(gè)條件開(kāi)始實(shí)際引用相同的條件。如果多個(gè)條件開(kāi)始實(shí)際包含相同的條件,流程引擎會(huì)拋出異常。
?????? 2.流程版本:如果部署一個(gè)新版的流程定義,之前版本的條件訂閱將會(huì)被取消。新版本中沒(méi)有提供的條件事件也會(huì)被取消。

?????? 條件開(kāi)始事件可以通過(guò)下面的方法觸發(fā):

List<ProcessInstance> instances = runtimeService
    .createConditionEvaluation()
    .setVariable("temperature", 24)
    .evaluateStartConditions();
// or
List<ProcessInstance> instances = runtimeService
    .createConditionEvaluation()
    .setVariables(variableMap)
    .evaluateStartConditions();

?????? 這些提供的變量被用作計(jì)算條件,也被傳遞到新的流程實(shí)例中作為變量。下面的xml表明,一個(gè)條件開(kāi)始事件是一個(gè)帶有conditionalEventDefinition子元素的普通事件
可選屬性:conditionalEventDefinition元素的可選屬性variableName允許指定一個(gè)變量名,這個(gè)變量名上的變量專(zhuān)門(mén)用作條件事件的執(zhí)行(be evaluated exclusively)

<startEvent id="conditionalStartEvent">
  <conditionalEventDefinition camunda:variableName="temperature">
    <condition type="tFormalExpression">${temperature > 20}</condition>
  </conditionalEventDefinition>
</startEvent>

五、事件子流程的條件開(kāi)始事件(Conditional Start Event for Event Sub Process):

?????? 與條件邊界事件類(lèi)似,對(duì)于事件子流程的條件開(kāi)始事件可以是可中斷的,也可以是不可中斷的
?????? 注意:事件子流程只能有一個(gè)開(kāi)始事件
?????? 下面的xml表明條件開(kāi)始事件是一個(gè)帶有conditionalEventDefinition子元素的普通開(kāi)始事件

<subProcess id="EventSubProcess" triggeredByEvent="true">
  <startEvent id="conditionalStartEvent">
    <conditionalEventDefinition>
      <condition type="tFormalExpression">${var1 == 1}</condition>
    </conditionalEventDefinition>
  </startEvent>
</subProcess>

六、觸發(fā)條件事件(Trigger Conditional Events):

?????? 觸發(fā)在作用域內(nèi)的實(shí)例化(Triggering on Scope Instantiation):
?????? 當(dāng)一個(gè)BPMN作用域被實(shí)例化,這個(gè)條件事件可以在這個(gè)作用域內(nèi)計(jì)算。這個(gè)行為叫做觸發(fā)作用域內(nèi)實(shí)例化。
考慮下面這個(gè)流程模型:
?????? 當(dāng)一個(gè)流程實(shí)例被發(fā)起,即這個(gè)流程定義的作用域被實(shí)例化了。條件子流程的條件將會(huì)在空開(kāi)始事件執(zhí)行之前被計(jì)算。如果滿足,它會(huì)立即出發(fā),并且空開(kāi)始事件將不會(huì)被執(zhí)行。這也同樣適用條件邊界事件和條件中間事件。

通過(guò)變量api進(jìn)行觸發(fā)(Triggering via Variable API):

??????除了在作用域?qū)嵗瘯r(shí)觸發(fā),條件事件也可以在流程變量發(fā)生改變時(shí)觸發(fā)。如果變量被創(chuàng)建更新和刪除。
從外部設(shè)置變量(Set Variable From Outside):
?????? 變量可以通過(guò)外部的變量api進(jìn)行修改。下面是一個(gè)在設(shè)置流程實(shí)例變量的例子:

//給流程實(shí)例設(shè)置變量set variable on process instance
runtimeService.setVariable(processInstance.getId(), "variable", 1);

通過(guò)委派代碼設(shè)置變量(Set Variable From Delegation Code):
?????? 變量不僅僅可以通過(guò)外部api設(shè)置,也可以通過(guò)委托代碼在流程實(shí)例內(nèi)部設(shè)置。

//例子:
public class SetVariableDelegate implements JavaDelegate {
  @Override
  public void execute(DelegateExecution execution) throws Exception {
    execution.setVariable("variable", 1);
  }
}

?????? 在委派代碼中設(shè)置時(shí),變量的改變不會(huì)立即觸發(fā)條件事件,以免干擾剩下的代碼的執(zhí)行,相反,更改在活動(dòng)實(shí)例生命周期的一個(gè)階段結(jié)束時(shí)被記錄并集體分派。
?????? 下面的圖展示了一個(gè)活動(dòng)實(shí)例的不同階段:


圖2:流程實(shí)例模型

1.開(kāi)始關(guān)聯(lián)到實(shí)例活動(dòng)的開(kāi)始階段,在這時(shí)會(huì)執(zhí)行輸入映射和調(diào)用執(zhí)行開(kāi)始監(jiān)聽(tīng)器
Starting corresponds to the starting phase of the activity instance. At this time the input mappings and execution start listeners are called.
2.執(zhí)行關(guān)聯(lián)到實(shí)例活動(dòng)的執(zhí)行階段
Execute corresponds to the executing phase of the activity instance.
3.結(jié)束關(guān)聯(lián)到實(shí)例活動(dòng)的結(jié)束階段,在這時(shí)會(huì)執(zhí)行輸出映射和調(diào)用執(zhí)行結(jié)束監(jiān)聽(tīng)器
Ending corresponds to the ending phase of the activity instance. At this time the output mappings and execution end listeners are called.

?????? 例如,假設(shè)變量在一個(gè)開(kāi)始執(zhí)行監(jiān)聽(tīng)活動(dòng)中被設(shè)置。條件事件會(huì)在所有的開(kāi)始監(jiān)聽(tīng)器被執(zhí)行后并且實(shí)例活動(dòng)已經(jīng)準(zhǔn)備進(jìn)入執(zhí)行階段.

七、自上而下執(zhí)行(Top-Down Evaluation):

?????? 變量的改變導(dǎo)致條件被重新計(jì)算,這個(gè)觸發(fā)重新計(jì)算的方式是自上而下的。這意味著計(jì)重新算在BPMN作用域的條件事件的條件被改變時(shí)開(kāi)始。然后一步一步的執(zhí)行到嵌套的BPMN作用域內(nèi)(被包含的子流程內(nèi))。這會(huì)一直執(zhí)行到一個(gè)條件事件被觸發(fā)然后回中斷當(dāng)前作用域內(nèi)的實(shí)例(取消所有的子流程)或者直到?jīng)]有更深的嵌套作用域。
?????? 例如下面的流程模型:


圖3:自上而下執(zhí)行

?????? 如果一個(gè)變量被設(shè)置到子流程的實(shí)例的context中,這個(gè)子流程的條件邊界事件首先被執(zhí)行。如果滿足條件,執(zhí)行就會(huì)被中斷,否則UserTask B的條件邊界事件在滿足條件的情況下會(huì)被觸發(fā)。

八、作用域計(jì)算(Scoped Evaluation):

?????? 當(dāng)實(shí)例作用域內(nèi)context的變量改變了,只會(huì)觸發(fā)變量是可見(jiàn)的條件事件,不會(huì)影響到不相關(guān)的作用域?qū)嵗?。這意味著如果變量改變,只有在實(shí)例作用域內(nèi)的context的條件事件的或者他們的子作用域的監(jiān)聽(tīng)會(huì)被計(jì)算。
?????? 例如下面的流程實(shí)例:


圖4:作用域內(nèi)計(jì)算

?????? 如果我們開(kāi)始了一個(gè)上面的流程實(shí)例,并且UserTask B和UserTask A是活動(dòng)的,那么此時(shí)流程實(shí)例活動(dòng)的層次關(guān)系是:

ProcessInstance
   UserTask A
   SubProcess
     UserTask B

?????? 如果流程變量被設(shè)置到子流程實(shí)例的context中,那么只有UserTask B的條件邊界事件會(huì)被執(zhí)行。UserTask A的邊界事件不會(huì)被觸發(fā),因?yàn)檫@個(gè)變量在這個(gè)context中不可見(jiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容