|
七、jBPM相關(guān)概念 1. JPDL的流程定義元素
1) 第一層:GraphElement
這個(gè)容易理解,因?yàn)樵诋?huà)流程定義時(shí),每個(gè)拖拉的對(duì)象都是一個(gè)graph的元素。GraphElement有四個(gè)屬性:
(1)processDefine 表示當(dāng)前元素屬于哪個(gè)流程定義
(2)events 表示可以接收哪些event
(3)name 名字
(4)exceptionHandlers 異常處理類(lèi)集合(List)
2) 第二層:node、processDefinition、Transition、Task
它們都繼承自GraphElement
(1)processDefinition表示流程定義(implements NodeCollection),它有下面的屬性:name、version、nodes、startState。nodes表示流程中所有的node,startState用于啟動(dòng)流程時(shí)找到首節(jié)點(diǎn)。
(2)Transition表示轉(zhuǎn)移,它有三個(gè)屬性:from(Node),to(Node),supportedEventTypes表示支持的event類(lèi)型
(3)node表示節(jié)點(diǎn),它有四個(gè)屬性:leaving transitions、arriving transitions、action、superState。
(4)Task 定義任務(wù)
3) 第三層:各種不同的node
它們都繼承自node。 Decision、EndState、Fork、Join、Merge、Milestone、 InterleaveEnd、InterleaveStart、ProcessState、State。
2. jBPM的token
jbpm中最重要的概念,應(yīng)該是令牌(Token)和信令(Signal)。在整個(gè)流程實(shí)例運(yùn)行過(guò)程中,我們可以迅速的利用token得到其當(dāng)前的current state。在解決“并行”等(比如Fork)問(wèn)題時(shí),jBpm讓Token對(duì)象維護(hù)了父子關(guān)系,這種關(guān)系在涉及到Fork的時(shí)候會(huì)產(chǎn)生。 jBpm讓Token這個(gè)對(duì)象身兼了多種使命:
(1)快速定位current state
(2)用于fork,join算法
(3)用于告知任務(wù)執(zhí)行者的任務(wù)索引。
如下代碼:
//pd是process definition,pi是process instance ProcessInstance pi = new ProcessInstance( pd ); //得到根令牌 Token token = pi.getRootToken(); //發(fā)信令 token.signal(); Token的signal方法也可以傳入transition參數(shù),這個(gè)方法把信令發(fā)送給Token,這樣,令牌將被激活,并沿指定的transition離開(kāi)當(dāng)前的狀態(tài)(如果沒(méi)有指定transition,將沿缺省的transition 離開(kāi)當(dāng)前狀態(tài))。 jbpm是怎么實(shí)現(xiàn)的呢?其實(shí)很簡(jiǎn)單:
1)Token記錄了當(dāng)前的狀態(tài)(current state),只有當(dāng)前的狀態(tài)(或稱(chēng)節(jié)點(diǎn))擁有該令牌 2)向TOKEN發(fā)signal后,當(dāng)前狀態(tài)收到該signal 3)當(dāng)前狀態(tài)把令牌傳給signal中指定的transition 4)transition收到令牌后,不強(qiáng)占,馬上把令牌傳給下個(gè)狀態(tài). 5)根據(jù)令牌的位置,流程的狀態(tài)已經(jīng)發(fā)生改變. 3. process definition
一個(gè)process definition代表了一個(gè)正式的業(yè)務(wù)流程,它以一個(gè)流程圖為基礎(chǔ)。這個(gè)流程圖由許多node和transition組成。每個(gè)node在這個(gè)流程圖里都有著各自特殊的類(lèi)型,這些不同的類(lèi)型決定了node在運(yùn)行時(shí)的不同行為。一個(gè)process definition只有一個(gè)start state 。
4. token
一個(gè)token代表了一條執(zhí)行路徑,它包含了這條執(zhí)行路徑的當(dāng)前的執(zhí)行狀態(tài)(current state)。
5. process instance
一個(gè)process instance(流程實(shí)例)即一個(gè)process definition(流程定義)的流程執(zhí)行實(shí)例。一個(gè)process definition可以對(duì)應(yīng)多個(gè)process instance。當(dāng)一個(gè)process instance被創(chuàng)建的時(shí)候,一個(gè)主執(zhí)行路徑token同時(shí)被創(chuàng)建,這個(gè)token叫做root token,它指向流程定義的start state(processDefinition.getStartState()==token.getNode())。
6. signal
一個(gè)signal 發(fā)送給token通知token 繼續(xù)流程的執(zhí)行。如果signal 沒(méi)有指定transition,token將沿缺省的transition離開(kāi)當(dāng)前狀態(tài),如果signal 指定transition,token將沿指定的transition離開(kāi)當(dāng)前的狀態(tài)??丛创a可以看到發(fā)給process instance的signal 其實(shí)都是發(fā)送給了root token。
7. Actions
jbpm提供了靈活的action ,當(dāng)流程執(zhí)行,token 進(jìn)入node和transition時(shí),會(huì)觸發(fā)相應(yīng)的一些event(事件)。在這些event上附上我們自己寫(xiě)的action,就會(huì)帶動(dòng)action 的執(zhí)行。action里是我們自己的相關(guān)java操作代碼,非常方便。注意的是event(事件)是內(nèi)置的,無(wú)法擴(kuò)展。另外,action也可以直接掛在node上,而不依賴(lài)于event(事件)的觸發(fā),這個(gè)很重要。
8. node
一個(gè)流程圖由許多node和transition組成。每個(gè)node都有一種類(lèi)型,這個(gè)類(lèi)型決定了當(dāng)流程執(zhí)行到這個(gè)node時(shí)的不同行為。jbpm有一組node type可以供你選擇,當(dāng)然你可以定制自己node 。
node的作用
node有兩個(gè)主要的作用:
1)執(zhí)行java代碼,比如說(shuō)創(chuàng)建task instance(任務(wù)實(shí)例)、發(fā)出通知、更新數(shù)據(jù)庫(kù)等等。很典型的就是在node 上掛上我們的action
2) 控制流程的執(zhí)行:
A、等待狀態(tài):流程進(jìn)入到這個(gè)node時(shí)將處于等待狀態(tài),直到一個(gè)signal 的發(fā)出
B、流程將沿著一個(gè)leaving transition越過(guò)這個(gè)node,這種情況特殊一點(diǎn),需要有個(gè)action掛在這個(gè)node上(注意這個(gè)action不是event觸發(fā)的!),action中將會(huì)調(diào)用到API里 executionContext.leaveNode(String transitionName),transitionName即這里的leaving transition名字。
C、創(chuàng)建新的執(zhí)行路徑:
很典型的就是fork node。流程在這里會(huì)分叉,產(chǎn)生新的執(zhí)行路徑。這樣就創(chuàng)建了新的token,每個(gè)新的token代表一個(gè)新的執(zhí)行路徑。注意的是,這些新的token和產(chǎn)生前的token是父子關(guān)系!
D、結(jié)束執(zhí)行路徑:一個(gè)node可以結(jié)束一條執(zhí)行路徑,這同樣意味著相應(yīng)的token的結(jié)束和流程的結(jié)束。
9. 流程圖中的node type
1) task-node
一個(gè)task-node可以包含一個(gè)或多個(gè)task,這些task分配給特定的user。當(dāng)流程執(zhí)行到task-node時(shí),task instance將會(huì)被創(chuàng)建,一個(gè)task對(duì)應(yīng)一個(gè)task instance。task instances 創(chuàng)建后,task-node就處于等待狀態(tài)。當(dāng)所有的task instances被特定的user執(zhí)行完畢后,將會(huì)發(fā)出一個(gè)新的signal 到token,即流程繼續(xù)執(zhí)行。
2) state
state是一個(gè)純粹的wait state(等待狀態(tài))。它和task-node的區(qū)別就是它不會(huì)創(chuàng)建task instances。很典型的用法是,當(dāng)進(jìn)入這個(gè)節(jié)點(diǎn)時(shí)(通過(guò)綁定一個(gè)action到node-enter event),發(fā)送一條消息到外部的系統(tǒng),然后流程就處于等待狀態(tài)。外部系統(tǒng)完成一些操作后返回一條消息,這個(gè)消息觸發(fā)一個(gè)signal 到token,然后流程繼續(xù)執(zhí)行。(不常用)
3) decision
當(dāng)需要在流程中根據(jù)不同條件來(lái)判斷執(zhí)行不同路徑時(shí),就可以用decision節(jié)點(diǎn)。兩種方法:最簡(jiǎn)單的是在transitions里增加condition elements(條件),condition是beanshell script寫(xiě)的,它返回一個(gè)boolean。當(dāng)運(yùn)行的時(shí)候,decision節(jié)點(diǎn)將會(huì)在它的 leaving transitions里循環(huán),同時(shí)比較 leaving transitions里的condition,最先返回‘true‘的condition,那個(gè)leaving transitions將會(huì)被執(zhí)行;作為選擇,你可以實(shí)現(xiàn)DecisionHandler接口,它有一個(gè)decide()方法,該方法返回一個(gè)String(leaving transition的名字)。
4) fork
fork節(jié)點(diǎn)把一條執(zhí)行路徑分離成多條同時(shí)進(jìn)行(并發(fā))的執(zhí)行路徑,每條離開(kāi)fork節(jié)點(diǎn)的路徑產(chǎn)生一個(gè)子token。
5) join
默認(rèn)情況下,join節(jié)點(diǎn)會(huì)認(rèn)為所有到達(dá)該節(jié)點(diǎn)的token都有著相同的父token。join 節(jié)點(diǎn)會(huì)結(jié)束每一個(gè)到達(dá)該節(jié)點(diǎn)的token,當(dāng)所有的子token都到達(dá)該節(jié)點(diǎn)后,父token會(huì)激活。當(dāng)仍然有子token處于活動(dòng)狀態(tài)時(shí),join 節(jié)點(diǎn)是wait state(等待狀態(tài))。
6) node
node節(jié)點(diǎn)就是讓你掛自己的action用的(注意:不是event觸發(fā)?。?dāng)流程到達(dá)該節(jié)點(diǎn)時(shí),action會(huì)被執(zhí)行。你的action要實(shí)現(xiàn)ActionHandler接口。同樣,在你的action里要控制流程。
10. Actions的說(shuō)明
存在兩種action,一種是 event觸發(fā)的action,一種是掛在node 節(jié)點(diǎn)的action。要注意它們的區(qū)別,event觸發(fā)的action無(wú)法控制流程,也就是說(shuō)它無(wú)法決定流程經(jīng)過(guò)這個(gè)節(jié)點(diǎn)后下一步將到哪一個(gè)leaving transition;而掛在node 節(jié)點(diǎn)的action就不同,它可以控制流程。不管是哪一種action都要實(shí)現(xiàn)ActionHandler接口。
11. Task(任務(wù))
jbpm一個(gè)相當(dāng)重要的功能就是對(duì)任務(wù)進(jìn)行管理。Task(任務(wù))是流程定義里的一部分,它決定了task instance的創(chuàng)建和分配。Task(任務(wù))可以在task-node節(jié)點(diǎn)下定義,也可以?huà)煸?/span>process-definition節(jié)點(diǎn)下。最普遍的方式是在task-node節(jié)點(diǎn)下定義一個(gè)或多個(gè)任務(wù)。默認(rèn)情況下,流程在task-node節(jié)點(diǎn)會(huì)處于等待狀態(tài),直到所有的任務(wù)被執(zhí)行完畢。任務(wù)的名稱(chēng)在整個(gè)流程中必須是唯一的。一個(gè)TaskNode對(duì)應(yīng)多個(gè)Task。
對(duì)于這樣的流程定義:
xml 代碼
對(duì)于這樣的流程定義: xml 代碼
對(duì)于這樣的流程定義: xml 代碼
對(duì)于這樣的流程定義: xml 代碼
12. jbpm的任務(wù)管理實(shí)現(xiàn)
一個(gè)Task instance(任務(wù)實(shí)例)可以被分配給一個(gè)actorId (java.lang.String)。所有的Task instance都被保存在數(shù)據(jù)庫(kù)中的表jbpm_taskinstance里。當(dāng)你想得到特定用戶(hù)的任務(wù)清單時(shí),你就可以通過(guò)一個(gè)與用戶(hù)關(guān)聯(lián)的actorId來(lái)查詢(xún)這張表。
一個(gè)流程定義有一個(gè)TaskMgmtDefinition;一個(gè)TaskMgmtDefinition對(duì)應(yīng)多個(gè)swimlane,同時(shí)對(duì)應(yīng)多個(gè)task;一個(gè)swimlane有多個(gè)task,可以從TaskMgmtDefinition中通過(guò)task的名稱(chēng)直接獲取相應(yīng)的task;
swimlane對(duì)象有四個(gè)屬性,分別是name(名字)、assignmentDelegation(分配代理類(lèi))、taskMgmtDefinition、tasks(Set 對(duì)應(yīng)多個(gè)task),可以增加task
task對(duì)象主要的屬性:taskMgmtDefinition、swimlane、assignmentDelegation、taskNode,需要注意的是swimlane和assignmentDelegation中間只是可以一個(gè)屬性有值,因?yàn)樗鼈兌己腿蝿?wù)的分配有關(guān)系。
一個(gè)流程實(shí)例有一個(gè)TaskMgmtInstance;一個(gè)TaskMgmtInstance對(duì)應(yīng)多個(gè)swimlaneInstance,同時(shí)對(duì)應(yīng)多個(gè)taskInstance;一個(gè)swimlaneInstance有多個(gè)taskInstance,可以從TaskMgmtInstance中直接獲取相應(yīng)的taskInstance;
swimlaneInstance對(duì)象主要有五個(gè)屬性,分別是name、actorId、pooledActors(Set)、swimlane、taskMgmtInstance。
taskInstance對(duì)象的主要屬性:name、actorId、task、swimlaneInstance、taskMgmtInstance、pooledActors。
當(dāng)對(duì)任務(wù)進(jìn)行分配時(shí),一般需要實(shí)現(xiàn)AssignmentHandler這個(gè)接口,這個(gè)接口的方法只有一個(gè):
void assign( Assignable assignable, ExecutionContext executionContext ) throws Exception;
一個(gè)典型的實(shí)現(xiàn)(把名字是‘change nappy‘的任務(wù)交給NappyAssignmentHandler這個(gè)類(lèi)來(lái)分配)
xml 代碼
1、流程進(jìn)入TaskNode節(jié)點(diǎn),執(zhí)行TaskNode類(lèi)的execute()方法,該方法首先獲得TaskMgmtInstance實(shí)例,然后通過(guò)它來(lái)創(chuàng)建TaskInstance。taskMgmtInstance.createTaskInstance(task, executionContext);
2、在上面的createTaskInstance(task, executionContext)里,該方法調(diào)用了taskInstance.assign(executionContext)對(duì)taskInstance進(jìn)行分配。
3、在assign(executionContext)方法里,首先會(huì)判斷task屬性里是否存在swimlane,如果有的話(huà),這個(gè)taskInstance就會(huì)分配給swimlane指定的ActorId或 PooledActors;如果不存在,再去找task屬性里 assignmentDelegation(分配代理類(lèi))通過(guò)代理類(lèi)(即我們自己寫(xiě)的實(shí)現(xiàn)AssignmentHandler這個(gè)接口的類(lèi))指定ActorId或 PooledActors。
13. jbpm的用戶(hù)角色管理
jbpm在用戶(hù)角色管理上共設(shè)計(jì)了四個(gè)類(lèi):Entity、Membership、Group、User。
Entity類(lèi)是其他三個(gè)類(lèi)的父類(lèi),它包含了兩個(gè)屬性:name(String)、permissions(Set);
User類(lèi)繼承Entity類(lèi),包含三個(gè)屬性:password(String)、email(String)、memberships(Set);
Group類(lèi)繼承Entity類(lèi),包含四個(gè)屬性: type(String)、parent(Group)、children(Set)、memberships(Set);
Membership類(lèi)繼承Entity類(lèi),包含三個(gè)屬性:role(String)、user(User)、group(Group)
很明顯,一個(gè)user對(duì)應(yīng)一個(gè)用戶(hù),一個(gè)group對(duì)應(yīng)一個(gè)用戶(hù)組,它們之間通過(guò)membership關(guān)聯(lián),并且一個(gè)user可以屬于多個(gè)不同類(lèi)型(type)的group,user和 group之間是多對(duì)多的關(guān)系。Membership類(lèi)的role屬性個(gè)人感覺(jué)用途不大,反倒是name屬性代表了user在group里的role(角色)。
|
|
|
來(lái)自: 夜郎 > 《workflow》