完整的jBPM4 PVM介紹發(fā)表在《程序員》第8期,這里截取部分的意思是 PVM的過程調(diào)度是非常靈活的,PVM提供了一套和token類似的execution過程調(diào)度機制,通過對execution的完全操控,節(jié)點運行期行為有了無限的可能 。
?
?
PVM的流程定義模型
首先要說明的是,上圖里的類全是接口。位于最上層的是ObservableElement,其提供給流程元素以附加Event(事件)的能力。在ObservableElementImpl里,它持有一個events的集合屬性。對于流程元素來說,典型的事件有:流程啟動/結(jié)束,節(jié)點啟動/結(jié)束和轉(zhuǎn)移線執(zhí)行(take)。
- protected ?Map<String,?EventImpl>?events;??
protected Map<String, EventImpl> events;
?
Event又做了些什么呢?EventImpl透過EventListenerReference實例的集合持有EventListener實例。這樣在引擎執(zhí)行過程調(diào)度時,就非常容易地通過流程元素本身獲取事件監(jiān)聽器并在相應(yīng)的時候執(zhí)行它們。
- protected ?List<EventListenerReference>?listenerReferences;??
protected List<EventListenerReference> listenerReferences;
?
和傳統(tǒng)的觀察者模式一致,EventListener接口有且只有一個方法:
- void ?notify(EventListenerExecution?execution)? throws ?Exception;??
void notify(EventListenerExecution execution) throws Exception;
?
緊接著ObservableElement的是CompositeElement,其擴展了ObservableElement接口。先看看它的方法:
- List<?? extends ?Activity>?getActivities(); ??
- ??
- boolean ?hasActivity(String?activityName); ??
- ??
- Activity?getActivity(String?activityName);??
List<? extends Activity> getActivities(); boolean hasActivity(String activityName); Activity getActivity(String activityName);
?
很明顯,它持有了Activity的集合,對于ProcessDefinition來說,這是一件很自然地事情:流程定義包含多個節(jié)點定義。重要的是Activity自身華麗的變身:節(jié)點定義實現(xiàn)了嵌套,出現(xiàn)了結(jié)構(gòu)塊。看圖說話:
這一設(shè)計在jBPM3里是沒有的,但是在jBPM4里則必須出現(xiàn),因為結(jié)構(gòu)塊是BPEL和BPMN里的重要概念。既然號稱PVM,則必須向BPEL和BPMN致敬。稍后我們可以看到,結(jié)構(gòu)塊的引入給引擎過程調(diào)度增加了很大的復(fù)雜度。在jPDL里,與之對應(yīng)的實現(xiàn)是group。這是jBPM4流程定義模型的最重要改變。
ProcessDefinition和Activity分別繼承自CompositeElement,Activity和Transition建立起雙向關(guān)聯(lián),這三者也是工作流模型里的標準建模。
PVM的過程調(diào)度
jBPM4采用execution來記錄當(dāng)前流程執(zhí)行的位置,并通過移動execution來推動流程的流轉(zhuǎn)。
- /**?transient?cached?current?activity?pointer.??persistence?is?managed?in?{@link?#activityName}?*/ ??
- private ?ActivityImpl?activity; ??
- ??
- /**?transition?is?not?to?be?made?persistable?by?default?*/ ??
- protected ?TransitionImpl?transition;??
/** transient cached current activity pointer. persistence is managed in {@link #activityName} */ private ActivityImpl activity; /** transition is not to be made persistable by default */ protected TransitionImpl transition;
?
execution通過activity和transition屬性來記錄位置。
execution是可以嵌套的,即會存在一種父子關(guān)系構(gòu)成樹狀結(jié)構(gòu),在任何時間,只有葉子execution處于活動狀態(tài)。最上層的execution稱為根execution,jBPM4里,根execution即為流程實例(在jBPM3里,記錄流程執(zhí)行位置的token和流程實例processInstance是獨立分開的)。
在兩種情況下,execution會產(chǎn)生子execution。一種情況是流程定義里存在并發(fā)路徑,此時execution會根據(jù)并發(fā)的路徑個數(shù)產(chǎn)生相應(yīng)的子execution,子execution執(zhí)行完畢并匯聚后則會觸發(fā)它們的父execution繼續(xù)流轉(zhuǎn)。另外一種情況是節(jié)點定義存在自己的變量定義和時間服務(wù)定義,則執(zhí)行該節(jié)點時會為該節(jié)點產(chǎn)生一個獨立的子execution,產(chǎn)生該execution的目的在于使得該節(jié)點擁有獨立的作用域,這個子execution也被稱為scope execution。節(jié)點執(zhí)行完畢后,與之關(guān)聯(lián)的scope execution將會被移除,同時,父execution被重新激活流轉(zhuǎn)。
1、 execution的移動
execution的移動操作被封裝在atomicOperation里。execution通過執(zhí)行atomicOperation來推動其的轉(zhuǎn)移。目前移動execution的atomicOperation有7種,如下圖所示:
ExecutionActivity執(zhí)行節(jié)點定義的運行期行為。節(jié)點的運行期行為委派給ActivityBehaviour實現(xiàn),當(dāng)需要對節(jié)點行為進行擴展時,需要實現(xiàn)ActivityBehaviour接口。jBPM4存在兩個對節(jié)點行為進行擴展的接口,分別是ActivityBehaviour和ExternalActivityBehaviour,ActivityBehaviour的execute方法在節(jié)點被執(zhí)行時調(diào)用;ExternalActivityBehaviour繼承自ActivityBehaviour,多出一個signal方法,在節(jié)點處于等待狀態(tài)被觸發(fā)流轉(zhuǎn)時調(diào)用。
- ActivityBehaviour?activityBehaviour?=?activity.getBehaviour(); ??
- ??
- activityBehaviour.execute(execution);??
ActivityBehaviour activityBehaviour = activity.getBehaviour(); activityBehaviour.execute(execution);
?
Signal執(zhí)行節(jié)點定義的運行期signal方法。
- ExternalActivityBehaviour?externalActivityBehaviour?=?????(ExternalActivityBehaviour)?activity.getBehaviour(); ??
- ??
- externalActivityBehaviour.signal(execution,signalName,?parameters);??
ExternalActivityBehaviour externalActivityBehaviour = (ExternalActivityBehaviour) activity.getBehaviour(); externalActivityBehaviour.signal(execution,signalName, parameters);
?
一個典型的signal方法會調(diào)用execution的take方法,從而將execution移動至給定的轉(zhuǎn)移線上。jPDL里StateActivity類的signal方法:
- execution.take(transition);??
execution.take(transition);
?
看看execution的take方法,設(shè)置execution位置并執(zhí)行TransitionEndActivity:
- //設(shè)置當(dāng)前execution的位置 ??
- setTransition((TransitionImpl)?transition); ??
- ???? //觸發(fā)事件,執(zhí)行TRANSITION_END_ACTIVITY原子操作 ??
- fire(Event.END,getActivity(),AtomicOperation. ??
- TRANSITION_END_ACTIVITY);??
//設(shè)置當(dāng)前execution的位置 setTransition((TransitionImpl) transition); //觸發(fā)事件,執(zhí)行TRANSITION_END_ACTIVITY原子操作 fire(Event.END,getActivity(),AtomicOperation. TRANSITION_END_ACTIVITY);
?
TransitionEndActivity銷毀移出節(jié)點的scope execution,接著執(zhí)行TransitionTake:
- //如果activity存在scope?execution的話,則銷毀,返回父execution ??
- if ?(activity.isLocalScope())?{ ??
- ??????propagatingExecution?=?execution.destroyScope(activity); ??
- ?????} ??
- //父execution執(zhí)行TRANSITION_TAKE原子操作 ??
- propagatingExecution.performAtomicOperation(AtomicOperation. ??
- ???TRANSITION_TAKE);??
//如果activity存在scope execution的話,則銷毀,返回父execution if (activity.isLocalScope()) { propagatingExecution = execution.destroyScope(activity); } //父execution執(zhí)行TRANSITION_TAKE原子操作 propagatingExecution.performAtomicOperation(AtomicOperation. TRANSITION_TAKE);
?
TransitionTake觸發(fā)轉(zhuǎn)移線的take事件,并執(zhí)行TransitionStartActivity:
- execution.fire(Event.TAKE,transition,AtomicOperation. ??
- ?????TRANSITION_START_ACTIVITY);??
execution.fire(Event.TAKE,transition,AtomicOperation. TRANSITION_START_ACTIVITY);
?
TransitionStartActivity設(shè)置execution位置為目標節(jié)點,創(chuàng)建scope execution并執(zhí)行ExecutionActivity:
- //設(shè)置當(dāng)前execution的位置 ??
- execution.setActivity(activity); ??
- ??
- ExecutionImpl?propagatingExecution?=?execution; ??
- //如果activity存在scope的話,則創(chuàng)建scope?execution ??
- ???? if ?(activity.isLocalScope())?{ ??
- ????????propagatingExecution?=?execution.createScope(activity); ??
- } ??
- ??
- propagatingExecution.setTransition( null ); ??
- //scope?execution執(zhí)行EXECUTE_ACTIVITY原子操作 ??
- propagatingExecution.performAtomicOperation(AtomicOperation. ??
- ????EXECUTE_ACTIVITY);??
//設(shè)置當(dāng)前execution的位置 execution.setActivity(activity); ExecutionImpl propagatingExecution = execution; //如果activity存在scope的話,則創(chuàng)建scope execution if (activity.isLocalScope()) { propagatingExecution = execution.createScope(activity); } propagatingExecution.setTransition(null); //scope execution執(zhí)行EXECUTE_ACTIVITY原子操作 propagatingExecution.performAtomicOperation(AtomicOperation. EXECUTE_ACTIVITY);
?
上述5種原子操作構(gòu)成了一個完整的execution節(jié)點間移動過程,分別是:執(zhí)行節(jié)點、觸發(fā)流轉(zhuǎn)、結(jié)束源節(jié)點、執(zhí)行轉(zhuǎn)移線和開始目標節(jié)點。如果節(jié)點是自動節(jié)點(沒有等待狀態(tài)),則觸發(fā)流轉(zhuǎn)(signal)這一步操作不會執(zhí)行。
存在結(jié)構(gòu)塊的情況下,TransitionEndActivity會依次觸發(fā)父節(jié)點的結(jié)束事件,前提是下一個目標節(jié)點未被父節(jié)點所包含,如果包含,則屬于結(jié)構(gòu)塊內(nèi)的節(jié)點移動;TransitionStartActivity會依次觸發(fā)父節(jié)點的開始事件,前提同樣是上一個源節(jié)點未被該父節(jié)點所包含,不屬于結(jié)構(gòu)塊內(nèi)的節(jié)點移動。
MoveToParentActivity使用在節(jié)點執(zhí)行或signal時沒有指定傳播方式,同時又找不到移出的轉(zhuǎn)移線時,會去執(zhí)行父節(jié)點的signal操作。MoveToChildActivity使用在節(jié)點含有子節(jié)點時,將execution轉(zhuǎn)移至子節(jié)點執(zhí)行。這兩種原子操作共同構(gòu)成了進入和結(jié)束結(jié)構(gòu)塊時execution的移動行為。
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
