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