jBPM3 vs jBPM4
JBoss Goup 目前已經(jīng)發(fā)布了 jBPM4 Alpha1 版本,在版本 4 中最大的變化就是引入 PVM (流程虛擬機(jī))的概念,而引擎內(nèi)部的調(diào)度算法中重要的 Token 機(jī)制,在新版中也去掉了,縱觀整個(gè)代碼,變化可以說(shuō)非常的大,筆者接下來(lái)就試著來(lái)比較一下這種變化,讓大家能有個(gè)直觀的認(rèn)識(shí)。當(dāng)然 Jbpm4 在 JBoss 的官方網(wǎng)站上的 Road map 中,在今年的 7 月 1 號(hào)才會(huì)發(fā)布第一個(gè)正式版本,因此后續(xù)可能還會(huì)有變化。
1、 ? 流程定義對(duì)象的變化:
Jbpm3 流程定義對(duì)象關(guān)系圖:
圖一 jbpm3流程定義對(duì)象關(guān)系圖
?
從上圖我們可以看出這 jbpm3 中, GraphElement 是流程圖中所有流程元素的父對(duì)象,而整個(gè)流程是由 ProcessDefinition 、 Node 、 Transition 三個(gè)主要對(duì)象構(gòu)成;
?
?圖二 PVM實(shí)體對(duì)象關(guān)系圖 ?????
?
?
從上圖可以看出,由于 PVM 概念的引入,所以在 jbpm3 中的 Graph 包在 jbpm4 中被移除了。在 pvm 中,在設(shè)計(jì)期,所有節(jié)點(diǎn)元素的父類為 ProcessElementImpl ,流程的主要組成元素 Nodelmpl 、 TransitionImpl 、 ProcessDefinitionImpl 、 EventImpl 則都直接或間接繼承自 ProcessElementImpl 。在運(yùn)行期: jbpm4 把流程的運(yùn)行期行為定義為執(zhí)行行為( ExecutionImpl )及原子操作行為( AtomicOperation ,其具體實(shí)現(xiàn)為 ExecuteNode 、 ProceedToDestination 、 TakeTranstion 、 MoveToParentNode 、 MoveToChildNode 、 signal ),其中 ExecutionImpl 是流程實(shí)例、活動(dòng)實(shí)例、事件監(jiān)聽器的所有執(zhí)行期行為的實(shí)現(xiàn)類。
?
圖三 jpdl 運(yùn)行期活動(dòng)實(shí)體對(duì)象關(guān)系圖
? 上圖是 jbpm4 在運(yùn)行期的活動(dòng)實(shí)例對(duì)象關(guān)系圖,從圖中我們可以看出,在運(yùn)行期, jbpm4 中定義了兩個(gè)活動(dòng)接口 Activity 和 ExternalActivity ,其中 ExternalActivity 繼承自 Activity 。 Activity 是所有自動(dòng)活動(dòng)節(jié)點(diǎn)的父接口,其實(shí)現(xiàn)類為 JpdlActivity ,而 JpdlActivity 又衍生出了、 StartActivity 、 JoinActivity 、 ForkActivity 、 EndActivity 、 CreateTimerActivity 、 JavaActivity 、 EsbActivity 等實(shí)例活動(dòng)對(duì)象。而 ExternalActivity 是具有等待狀態(tài)的活動(dòng)( StateActivity )父接口,像人工活動(dòng) TaskActivity 就是實(shí)現(xiàn)了此接口。
? 2、 ? 核心引擎的調(diào)度算法
Jbpm3 的核心調(diào)度算法是基于 Token 機(jī)制的,在運(yùn)行期這個(gè) Token 在 Node Instance 之間流轉(zhuǎn),依靠 Token 的觸發(fā)來(lái)推進(jìn)流程。具體的調(diào)度機(jī)制,可參加胡長(zhǎng)城的文章( http://blog.csdn.net/james999/archive/2007/09/02/1769592.aspx );其實(shí)這個(gè) Token 來(lái)自于 Pertri-net ,感興趣的讀者可以去看 Pertri-net 中的 Token 及 Place 。
?
圖四 jbpm3引擎調(diào)度圖 ?
Jbpm4 則去掉了 Token ,那么它的核心調(diào)度機(jī)制是怎樣實(shí)現(xiàn)的呢?
?圖五 jbpm4流程啟動(dòng)序列圖
圖六 jbpm4 流程推進(jìn)序列圖
圖五是在 jbpm4 中啟動(dòng)一個(gè)流程實(shí)例的執(zhí)行序列圖,圖六是節(jié)點(diǎn)推進(jìn)的執(zhí)行序列圖,從上面兩個(gè)圖中我們可以看到核心的調(diào)度是依據(jù) Execution 的轉(zhuǎn)移來(lái)實(shí)現(xiàn)的( ExecutionImpl 可以是 ActivityExecution 、 ClientProcessInstance 、 EventListenerExecution 的實(shí)例), Execution 實(shí)際上就是取代了 Jbpm3 中的 Token , Execution 的轉(zhuǎn)移實(shí)際上就是根據(jù)狀態(tài)機(jī)的變遷( ActivityExecution 、 ClientProcessInstance 、 EventListenerExecution 實(shí)例之間的切換)加上調(diào)用相應(yīng)的原子操作: ExecuteNode 、 MoveToChildNode 、 MoveToParentNode 、 ProceedToDesitination 、 Signal 、 TakeTransition (詳見 pvm/internal/model/op 包下的相關(guān)類)來(lái)實(shí)現(xiàn)的。所以 Execution 實(shí)例的集合及有向圖實(shí)際上就是運(yùn)行期的路徑。
?
3、 ? Event-Action 機(jī)制的變化
在 jbpm3 中是基于 Event-Action 機(jī)制來(lái)實(shí)現(xiàn)事件與動(dòng)作的觸發(fā)的,但是在 jbpm4 中則采用觀察者模式來(lái)觸發(fā)事件的。所有用戶自己定義的動(dòng)作,全部要實(shí)現(xiàn) EventListener 接口,這些動(dòng)作作為監(jiān)聽者(就是事件 Event 的觀察者 Observer )注冊(cè)到相應(yīng)的流程定義對(duì)象上( ProcessElement 或者 Node ),而事件 Event 則作為被觀察的對(duì)象(實(shí)際上就是 Observerable ),實(shí)際上在 jbpm4 中專門定義出了一個(gè)對(duì)象 ObservableElementImpl ,流程定義中的 NodeImpl 、 TransitionImpl 、 ProcessDefinitionImpl 均繼承自此對(duì)象,因此這些元素本身就可以作為 Observerable 而被觀察者來(lái)監(jiān)控。
4、 ? 客戶端接口的變化
在 jbpm4 中對(duì)客戶端的接口統(tǒng)一為 7 個(gè)服務(wù)接口: ProcessService 、 ExecutionService 、 CommandService 、 TaskService 、 ManagementService 、 HistoryService 、 IdentityService ,這 7 個(gè)接口可以從 ProcessEngine 接口中獲得, jbpm4 在啟動(dòng)的過程中由 JbpmConfiguration 負(fù)責(zé)構(gòu)建引擎。
?? ProcessService- 流程定義的服務(wù)接口,包括對(duì)流程定義的部署、查詢、刪除操作;
?? ExecutionService- 執(zhí)行服務(wù)接口,包括啟動(dòng)流程、實(shí)例推進(jìn)、設(shè)置變量等操作;
?? CommandService-Command 模式的服務(wù)接口,實(shí)際上就是將客戶端的請(qǐng)求全部封裝在一個(gè)調(diào)用接口中,然后由這個(gè)接口去調(diào)用 Command 接口的眾多實(shí)現(xiàn)( StartExecutionCmd 、 SignalCmd 、 SetVariablesCmd 、 GetTimersCmd 、 DeployCmd 、 NewTaskCmd 、 SubmitTask 、 ExecuteJobCmd 等等,具體可參加 pvm/internal/cmd , task/internal/cmd 包及其它包下實(shí)現(xiàn) Command 接口的類),這是典型的 Command 模式的應(yīng)用,感興趣的讀者可以去了解設(shè)計(jì)模式中的 Command 模式;
?? TaskService- 人工活動(dòng)的服務(wù)接口,包括對(duì)任務(wù)的創(chuàng)建、提交、查詢、保存、刪除等操作;
?? ManagementService-web 管理控制臺(tái)的服務(wù)接口,目前只有獲得消息及計(jì)時(shí)器的接口實(shí)現(xiàn);
?? HistoryService- 目前有對(duì)歷史庫(kù)中的流程實(shí)例、活動(dòng)實(shí)例進(jìn)行查詢、某個(gè)流程定義中的所有活動(dòng)的平均持續(xù)時(shí)間、某個(gè)流程定義中的某個(gè)活動(dòng)實(shí)例的轉(zhuǎn)移的執(zhí)行次數(shù)
?? IdentityService- 用戶、組、成員關(guān)系的相關(guān)操作方法
?
5、 歷史庫(kù)的加入
jBPM3 中數(shù)據(jù)庫(kù)設(shè)計(jì)一直是我比較詬病的地方,尤其是其實(shí)例數(shù)據(jù)庫(kù)沒有設(shè)計(jì)歷史庫(kù)的概念并按照辦結(jié)狀態(tài)將運(yùn)行結(jié)束的實(shí)例數(shù)據(jù)歸入歷史庫(kù),在這種情況下它的實(shí)例數(shù)據(jù)庫(kù)就會(huì)隨著時(shí)間而無(wú)限膨脹,這就阻礙了它的真實(shí)應(yīng)用,而在 jBPM4 的最新代碼中(注意 Alpha1 還沒有出現(xiàn)),歷史庫(kù)的相關(guān)功能代碼竟然出現(xiàn)了!詳見 ExecutionImpl 最新代碼中的 fireHistoryEvent 方法及一系列的 historyXXX 方法。在 ActivityBehaviour 的 execute 方法中加入了 historyTaskStart 方法的調(diào)用、 signal 方法中加入了 historyTaskEnd 方法的調(diào)用,而以上 2 個(gè)方法在 ExecutionImpl 中都是以歷史事件( HistoryEvent 有 4 個(gè)實(shí)現(xiàn)子類 ProcessInstanceStart 、 ProcessInstanceEnd 、 ActivityStart 、 ActivityEnd 分別用作流程實(shí)例的創(chuàng)建結(jié)束期、活動(dòng)實(shí)例的創(chuàng)建結(jié)束期的歷史數(shù)據(jù)處理)的觸發(fā)機(jī)制來(lái)實(shí)現(xiàn)的,也就是在整個(gè)流程實(shí)例執(zhí)行的過程中,都加入了對(duì)將運(yùn)行數(shù)據(jù)存入歷史庫(kù)的歷史事件( HistoryEvent )的觸發(fā)。這樣實(shí)例列表的查詢可以只查詢歷史庫(kù)。不過這里很遺憾的是,這個(gè)事件沒有同時(shí)清除運(yùn)行庫(kù)的數(shù)據(jù),這樣還是會(huì)造成運(yùn)行庫(kù)的無(wú)限膨脹問題。