事件(Event)
事件用來(lái)表明流程的生命周期中發(fā)生了什么事. 事件總是畫(huà)成一個(gè)圓圈.
在BPMN 2.0中, 事件有兩大分類(lèi): 捕獲(catching)或 觸發(fā)(throwing) 事件.
捕獲(Catching): 當(dāng)流程執(zhí)行到事件, 它會(huì)等待被觸發(fā). 觸發(fā)的類(lèi)型是由內(nèi)部圖表或XML中的類(lèi)型聲明來(lái)決定的. 捕獲事件與觸發(fā)事件在顯示方面是根據(jù)內(nèi)部圖表是否被填充來(lái)區(qū)分的(白色的).
觸發(fā)(Throwing): 當(dāng)流程執(zhí)行到事件, 會(huì)觸發(fā)一個(gè)事件. 觸發(fā)的類(lèi)型是由內(nèi)部圖表或XML中的類(lèi)型聲明來(lái)決定的. 觸發(fā)事件與捕獲事件在顯示方面是根據(jù)內(nèi)部圖表是否被填充來(lái)區(qū)分的(被填充為黑色).
事件定義
事件定義, 決定了事件的語(yǔ)義. 如果沒(méi)有事件定義, 這個(gè)事件就不做什么特別的事情.
沒(méi)有設(shè)置事件定義的開(kāi)始事件不會(huì)在啟動(dòng)流程時(shí)做任何事情. 如果給開(kāi)始事件添加了一個(gè)事件定義(比如定時(shí)器事件定義)我們就聲明了開(kāi)始流程的事件 "類(lèi)型 " (這時(shí)定時(shí)器事件監(jiān)聽(tīng)器會(huì)在某個(gè)時(shí)間被觸發(fā)).
定時(shí)器事件定義
定時(shí)器事件是根據(jù)指定的時(shí)間觸發(fā)的事件。可以用于開(kāi)始事件, 中間事件或邊界事件.
timeDate: ISO 8601格式指定一個(gè)確定的時(shí)間, 觸發(fā)事件的時(shí)間.示例:
<timerEventDefinition>
<timeDate>2011-03-11T12:13:14</timeDate>
</timerEventDefinition>
timeDuration: 指定定時(shí)器之前要等待多長(zhǎng)時(shí)間, timeDuration可以設(shè)置為timerEventDefinition的子元素. 使用ISO 8601規(guī)定的格式 (由BPMN 2.0規(guī)定)。示例(等待10天)。
<timerEventDefinition>
<timeDuration>P10D</timeDuration>
</timerEventDefinition>
timeCycle: 指定重復(fù)執(zhí)行的間隔, 可以用來(lái)定期啟動(dòng)流程實(shí)例, 或?yàn)槌瑫r(shí)時(shí)間發(fā)送多個(gè)提醒. timeCycle元素可以使用兩種格式, 第一種是
ISO 8601標(biāo)準(zhǔn)的格式. 示例(重復(fù)3次,每次間隔10小時(shí)):
<timerEventDefinition>
<timeCycle>R3/PT10H</timeCycle>
</timerEventDefinition>
另外, 你可以使用cron表達(dá)式指定timeCycle, 下面的例子是從整點(diǎn)開(kāi)始, 每5分鐘執(zhí)行一次:
0 0/5 * * * ?
注意: 第一個(gè)數(shù)字表示秒,而不是像通常Unix cron中那樣表示分鐘.
你可以在定時(shí)器事件定義中使用表達(dá)式, 這樣你就可以通過(guò)流程變量來(lái)影響那個(gè)定時(shí)器定義. 流程定義必須包含ISO 8601(或cron)格式的字符串, 以匹配對(duì)應(yīng)的時(shí)間類(lèi)型.
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
<timerEventDefinition>
<timeDuration>${duration}</timeDuration>
</timerEventDefinition>
</boundaryEvent>
注意: 計(jì)時(shí)器,只有當(dāng)啟用了異步執(zhí)行(flowable.cfg.xml中的asyncExecutorActivate需要設(shè)置為true, 因?yàn)楫惒綀?zhí)行默認(rèn)情況下禁用的).
開(kāi)始事件
開(kāi)始事件用來(lái)指明流程在哪里開(kāi)始. 開(kāi)始事件的類(lèi)型(消息到達(dá)時(shí)開(kāi)始還是等待特定時(shí)間間隔 等等), 定義了流程如何啟動(dòng), 這通過(guò)事件中不同的小圖表來(lái)展示. 在XML中, 這些類(lèi)型是通過(guò)聲明不同的子元素來(lái)區(qū)分的.
開(kāi)始事件都是捕獲事件: 最終這些事件都是(一直)等待著, 直到對(duì)應(yīng)的觸發(fā)時(shí)機(jī)出現(xiàn).
在啟動(dòng)事件中, 可以指定以下Flowable特定屬性:
initiator: 當(dāng)流程啟動(dòng)時(shí), 保存經(jīng)過(guò)身份驗(yàn)證的用戶標(biāo)識(shí)的變量名稱. 示例如下:
<startEvent id="request" flowable:initiator="initiator" />
經(jīng)過(guò)身份驗(yàn)證的用戶必須使用IdentityService.setAuthenticatedUserId(String)
try-finally
塊中的方法進(jìn)行設(shè)置, 如下所示:
try {
identityService.setAuthenticatedUserId("bono");
runtimeService.startProcessInstanceByKey("someProcessKey");
} finally {
identityService.setAuthenticatedUserId(null);
}
空開(kāi)始事件
空開(kāi)始事件技術(shù)上意味著沒(méi)有指定啟動(dòng)流程實(shí)例的觸發(fā)條件. 這就是說(shuō)引擎不能預(yù)計(jì)什么時(shí)候流程實(shí)例會(huì)啟動(dòng). 空開(kāi)始事件用于, 當(dāng)流程實(shí)例要通過(guò)API啟動(dòng)的場(chǎng)景, 通過(guò)調(diào)用startProcessInstanceByXXX
方法.
ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();
圖形表示法
空開(kāi)始事件顯示成一個(gè)圓圈,沒(méi)有內(nèi)部圖表(沒(méi)有觸發(fā)類(lèi)型)
XML表示
空開(kāi)始事件的XML結(jié)構(gòu)是普通的開(kāi)始事件定義, 沒(méi)有任何子元素(其他開(kāi)始事件類(lèi)型都有一個(gè)子元素來(lái)聲明自己的類(lèi)型)
<startEvent id="start" name="my start event" />
計(jì)時(shí)器開(kāi)始事件
定時(shí)開(kāi)始事件用來(lái)在指定的時(shí)間創(chuàng)建流程實(shí)例. 它可以同時(shí)用于只啟動(dòng)一次流程和應(yīng)該在特定時(shí)間間隔啟動(dòng)多次的流程.
注意: 子流程不能使用定時(shí)開(kāi)始事件.
注意: 定時(shí)開(kāi)始事件在流程發(fā)布后就會(huì)開(kāi)始計(jì)算時(shí)間. 不需要調(diào)用startProcessInstanceByXXX
, 雖然也可以調(diào)用啟動(dòng)流程的方法, 但是那會(huì)導(dǎo)致調(diào)用startProcessInstanceByXXX
時(shí)啟動(dòng)過(guò)多的流程
注意: 當(dāng)包含定時(shí)開(kāi)始事件的新版本流程部署時(shí), 對(duì)應(yīng)的上一個(gè)定時(shí)器就會(huì)被刪除. 這是因?yàn)橥ǔ2幌M詣?dòng)啟動(dòng)舊版本流程的流程實(shí)例.
圖形表示法
定時(shí)開(kāi)始事件顯示為了一個(gè)圓圈, 內(nèi)部是一個(gè)表.
XML內(nèi)容
定時(shí)開(kāi)始事件的XML內(nèi)容是普通開(kāi)始事件的聲明, 包含一個(gè)定時(shí)定義子元素.請(qǐng)參考定時(shí)定義查看配合細(xì)節(jié).
示例: 流程會(huì)啟動(dòng)4次, 每次間隔5分鐘, 從2011年3月11日 12:13開(kāi)始計(jì)時(shí).
<startEvent id="theStart">
<timerEventDefinition>
<timeCycle>R4/2011-03-11T12:13/PT5M</timeCycle>
</timerEventDefinition>
</startEvent>
例如: 進(jìn)程將在選定的日期開(kāi)始一次
<startEvent id="theStart">
<timerEventDefinition>
<timeDate>2011-03-11T12:13:14</timeDate>
</timerEventDefinition>
</startEvent>
順序流
順序流是連接兩個(gè)流程節(jié)點(diǎn)的連線. 流程執(zhí)行完一個(gè)節(jié)點(diǎn)后, 會(huì)沿著節(jié)點(diǎn)的所有外出順序流繼續(xù)執(zhí)行.
圖形標(biāo)記
順序流顯示為從起點(diǎn)到終點(diǎn)的箭頭. 箭頭總是指向終點(diǎn).
XML內(nèi)容
順序流需要流程范圍內(nèi)唯一的id, 以及對(duì)起點(diǎn)與終點(diǎn)元素的引用.
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
條件順序流
可以為順序流定義一個(gè)條件. 離開(kāi)一個(gè)BPMN 2.0節(jié)點(diǎn)時(shí), 默認(rèn)會(huì)計(jì)算外出順序流的條件. 如果條件結(jié)果為true, 就會(huì)選擇外出順序流繼續(xù)執(zhí)行. 當(dāng)多條順序流被選中時(shí), 就會(huì)創(chuàng)建多條分支, 流程會(huì)繼續(xù)以并行方式繼續(xù)執(zhí)行.
注意: 上面的討論僅涉及BPMN 2.0節(jié)點(diǎn)(和事件), 不包括網(wǎng)關(guān). 網(wǎng)關(guān)會(huì)用特定的方式處理順序流中的條件, 這與網(wǎng)關(guān)類(lèi)型相關(guān).
圖形標(biāo)記
條件順序流顯示為一個(gè)正常的順序流, 不過(guò)在起點(diǎn)有一個(gè)菱形. 條件表達(dá)式也會(huì)顯示在順序流上.
XML內(nèi)容
條件順序流定義為一個(gè)正常的順序流, 包含conditionExpression
子元素.
注意目前只支持tFormalExpressions
, 如果沒(méi)有設(shè)置xsi:type=""
, 就會(huì)默認(rèn)值支持目前支持的表達(dá)式類(lèi)型.
<sequenceFlow id="flow" sourceRef="theStart" targetRef="theTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.price > 100 && order.price < 250}]]>
</conditionExpression>
</sequenceFlow>
目前, conditionalExpressions
只能與UEL一起使用.
下面的例子引用了流程變量的數(shù)據(jù), 通過(guò)getter調(diào)用JavaBean.
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.price > 100 && order.price < 250}]]>
</conditionExpression>
這個(gè)例子調(diào)用一個(gè)解析為布爾值的方法
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.isStandardOrder()}]]>
</conditionExpression>
網(wǎng)關(guān)
網(wǎng)關(guān)用來(lái)控制流程的流向.
圖形標(biāo)記
網(wǎng)關(guān)顯示成菱形圖形, 內(nèi)部有一個(gè)小圖標(biāo). 圖標(biāo)表示網(wǎng)關(guān)的類(lèi)型.
獨(dú)占網(wǎng)關(guān)
獨(dú)占網(wǎng)關(guān)(也叫異或(XOR)網(wǎng)關(guān)), 用來(lái)在流程中實(shí)現(xiàn)決策.
當(dāng)流程執(zhí)行到這個(gè)網(wǎng)關(guān), 所有外出順序流都會(huì)被處理一遍. 其中條件解析為true的順序流(或者沒(méi)有設(shè)置條件, 概念上在順序流上定義了一個(gè)'true')會(huì)被選中,讓流程繼續(xù)運(yùn)行.
注意這里的外出順序流與BPMN 2.0通常的概念是不同的. 通常情況下, 所有條件結(jié)果為true的順序流都會(huì)被選中, 以并行方式執(zhí)行, 但獨(dú)占網(wǎng)關(guān)只會(huì)選擇一條順序流執(zhí)行. 就是說(shuō), 雖然多個(gè)順序流的條件結(jié)果為true, 那么XML中的第一個(gè)順序流(也只有這一條)會(huì)被選中, 并用來(lái)繼續(xù)運(yùn)行流程. 如果沒(méi)有選中任何順序流, 會(huì)拋出一個(gè)異常.
圖形標(biāo)記
獨(dú)占網(wǎng)關(guān)顯示成一個(gè)普通網(wǎng)關(guān)()比如,菱形圖形), 內(nèi)部是一個(gè)“X”圖標(biāo), 表示異或(XOR)語(yǔ)義. 注意, 沒(méi)有內(nèi)部圖標(biāo)的網(wǎng)關(guān), 默認(rèn)為獨(dú)占網(wǎng)關(guān). BPMN 2.0規(guī)范不允許在同一個(gè)流程定義中同時(shí)使用沒(méi)有X和有X的菱形圖形.
XML內(nèi)容
獨(dú)占網(wǎng)關(guān)的XML內(nèi)容是很直接的: 用一行定義了網(wǎng)關(guān), 條件表達(dá)式定義在外出順序流中. 參考條件順序流獲得這些表達(dá)式的可用配置.
參考下面模型實(shí)例
它對(duì)應(yīng)的XML內(nèi)容如下:
<exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" />
<sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">
<conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">
<conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">
<conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>
</sequenceFlow>
任務(wù)
用戶任務(wù)
用戶任務(wù)用來(lái)設(shè)置必須由人員完成的工作. 當(dāng)流程執(zhí)行到用戶任務(wù), 會(huì)創(chuàng)建一個(gè)新任務(wù), 并把這個(gè)新任務(wù)加入到分配人或群組的任務(wù)列表中.
圖形標(biāo)記
用戶任務(wù)顯示成一個(gè)普通任務(wù)(圓角矩形), 左上角有一個(gè)小用戶圖標(biāo).
XML內(nèi)容
XML中的用戶任務(wù)定義如下. id屬性是必須的. name屬性是可選的.
<userTask id="theTask" name="Important task" />
用戶任務(wù)也可以設(shè)置描述.實(shí)際上所有BPMN 2.0元素都可以設(shè)置描述.
添加documentation元素可以定義描述.
<userTask id="theTask" name="Schedule meeting" >
<documentation>
Schedule an engineering meeting for next week with the new hire.
</documentation>
...
描述文本可以用標(biāo)準(zhǔn)的Java方式從任務(wù)中獲取:
task.getDescription()
持續(xù)時(shí)間
任務(wù)可以用一個(gè)字段來(lái)描述任務(wù)的持續(xù)時(shí)間. 可以使用查詢API來(lái)對(duì)持續(xù)時(shí)間進(jìn)行搜索, 根據(jù)在時(shí)間之前或之后進(jìn)行搜索.
我們提供了一個(gè)節(jié)點(diǎn)擴(kuò)展, 在任務(wù)定義中設(shè)置一個(gè)表達(dá)式, 這樣在任務(wù)創(chuàng)建時(shí)就可以為它設(shè)置初始持續(xù)時(shí)間. 表達(dá)式應(yīng)該是java.util.Date
, java.util.String (ISO8601格式)
, ISO8601持續(xù)時(shí)間(比如PT50M)或null.
例如: 你可以在流程中使用上述格式輸入日期, 或在前一個(gè)服務(wù)任務(wù)中計(jì)算一個(gè)時(shí)間. 這里使用了持續(xù)時(shí)間, 持續(xù)時(shí)間會(huì)基于當(dāng)前時(shí)間進(jìn)行計(jì)算, 再通過(guò)給定的時(shí)間段累加. 比如, 使用"PT30M"作為持續(xù)時(shí)間, 任務(wù)就會(huì)從現(xiàn)在開(kāi)始持續(xù)30分鐘.
<userTask id="theTask" name="Important task" flowable:dueDate="${dateVariable}"/>
任務(wù)的持續(xù)時(shí)間也可以通過(guò)TaskService修改或在TaskListener中通過(guò)傳入的DelegateTask參數(shù)修改.
用戶分配
用戶任務(wù)可以直接分配給一個(gè)用戶. 這可以通過(guò)humanPerformer元素定義. humanPerformer定義需要一個(gè) resourceAssignmentExpression來(lái)實(shí)際定義用戶. 當(dāng)前, 只支持formalExpressions.
<process >
...
<userTask id='theTask' name='important task' >
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>kermit</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
</userTask>
只有一個(gè)用戶可以坐擁任務(wù)的執(zhí)行者分配給用戶. 在Flowable中, 用戶叫做執(zhí)行者. 擁有執(zhí)行者的用戶不會(huì)出現(xiàn)在其他人的任務(wù)列表中, 只能出現(xiàn)執(zhí)行者的個(gè)人任務(wù)列表中.
直接分配給用戶的任務(wù)可以通過(guò)TaskService像下面這樣獲取:
List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list();
任務(wù)也可以加入到人員的候選任務(wù)列表中. 這時(shí), 需要使用potentialOwner 元素. 用法和humanPerformer元素類(lèi)似. 注意它需要指定表達(dá)式中的每個(gè)項(xiàng)目是人員還是群組 .
<process >
...
<userTask id='theTask' name='important task' >
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>user(kermit), group(management)</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
使用potentialOwner元素定義的任務(wù), 可以像下面這樣獲取(使用TaskQuery的發(fā)那個(gè)發(fā)與查詢?cè)O(shè)置了執(zhí)行者的任務(wù)類(lèi)似):
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit");
任務(wù)分配擴(kuò)展
當(dāng)分配不復(fù)雜時(shí), 用戶和組的設(shè)置非常麻煩. 為避免復(fù)雜性,可以使用用戶任務(wù)的自定義擴(kuò)展.
assignee屬性: 這個(gè)自定義擴(kuò)展可以直接把用戶任務(wù)分配給指定用戶.
<userTask id="theTask" name="my task" flowable:assignee="kermit" />
它和使用上面定義的humanPerformer效果完全一樣.
candidateUsers屬性: 這個(gè)自定義擴(kuò)展可以為任務(wù)設(shè)置候選人.
<userTask id="theTask" name="my task" flowable:candidateUsers="kermit, gonzo" />
它和使用上面定義的potentialOwner效果完全一樣. 注意它不需要像使用potentialOwner通過(guò)user(kermit)聲明, 因?yàn)檫@個(gè)屬性只能用于人員.
candidateGroups屬性: 這個(gè)自定義擴(kuò)展可以為任務(wù)設(shè)置候選組.
<userTask id="theTask" name="my task" flowable:candidateGroups="management, accountancy" />
它和使用上面定義的potentialOwner效果完全一樣. 注意它不需要像使用potentialOwner通過(guò)group(management)聲明, 因?yàn)檫@個(gè)屬性只能用于群組.
candidateUsers 和 candidateGroups 可以同時(shí)設(shè)置在同一個(gè)用戶任務(wù)中.
Java服務(wù)任務(wù)
java服務(wù)任務(wù)用來(lái)調(diào)用外部java類(lèi).
圖形標(biāo)記
服務(wù)任務(wù)顯示為圓角矩形, 左上角有一個(gè)齒輪小圖標(biāo).
XML內(nèi)容
有4鐘方法來(lái)聲明java調(diào)用邏輯:
- 實(shí)現(xiàn)JavaDelegate或ActivityBehavior
- 執(zhí)行解析代理對(duì)象的表達(dá)式
- 調(diào)用一個(gè)方法表達(dá)式
- 調(diào)用一直值表達(dá)式
執(zhí)行一個(gè)在流程執(zhí)行中調(diào)用的類(lèi), 需要在'flowable:class'屬性中設(shè)置全類(lèi)名.
<serviceTask id="javaService"
name="My Java Service Task"
flowable:class="org.flowable.MyJavaDelegate" />
也可以使用表達(dá)式調(diào)用一個(gè)對(duì)象. 對(duì)象必須遵循一些規(guī)則, 并使用flowable:class
屬性進(jìn)行創(chuàng)建.
<serviceTask id="serviceTask" flowable:delegateExpression="${delegateExpressionBean}" />
這里delegateExpressionBean
是一個(gè)bean, 它實(shí)現(xiàn)了JavaDelegate在Spring容器中定義的接口.
要指定應(yīng)評(píng)估的UEL方法表達(dá)式, 請(qǐng)使用屬性flowable:expression
<serviceTask id="javaService"
name="My Java Service Task"
flowable:expression="#{printer.printMessage()}" />
printMessage將在名為的命名對(duì)象上調(diào)用方法(不帶參數(shù))printer.
也可以使用表達(dá)式中使用的方法傳遞參數(shù):
<serviceTask id="javaService"
name="My Java Service Task"
flowable:expression="#{printer.printMessage(execution, myVar)}" />
這會(huì)調(diào)用名為printer對(duì)象上的方法printMessage. 第一個(gè)參數(shù)是DelegateExecution, 在表達(dá)式環(huán)境中默認(rèn)名稱為execution. 第二個(gè)參數(shù)傳遞的是當(dāng)前流程的名為myVar的變量.
要指定執(zhí)行的UEL值表達(dá)式, 需要使用flowable:expression
屬性.
<serviceTask id="javaService"
name="My Java Service Task"
flowable:expression="#{split.ready}" />
ready屬性的getter方法, getReady(無(wú)參數(shù)), 會(huì)作用于名為split的bean上. 這個(gè)對(duì)象會(huì)被解析為流程對(duì)象和(如果合適)spring環(huán)境中的對(duì)象.
這里我只寫(xiě)了一部分, 大家可以參考這兩個(gè)網(wǎng)址來(lái)學(xué)習(xí)網(wǎng)址1 網(wǎng)址2