应用jBPM4解决中国特色的流程需求 (看过之后,强烈推荐)
jBPM是JBoss眾多開源項目中的一個工作流開源項目,也是目前應用最廣泛的工作流項目。在今年的7月10號,JBoss jBPM團隊正式發布了jBPM4的正式版。jBPM4完全基于流程虛擬機(PVM)的機制,對核心引擎進行了重新設計,而PVM的引入也使得jBPM4可以支持多流程語言了。除此之外還有很多其它的特點:
- 流程定義對象的變化
在流程定義的對象上,節點類型劃分更清晰,詳細的對象解析,可參見我曾經寫過的文章:《jBPM3與jBPM4實現對比》。 - 基于觀察者模式的Event-Listener機制
在jBPM4中活動節點對象ActivityImpl、轉移對象TransitionImpl、流程定義對象ProcessDefinitionImpl,全部繼承了ObservableElementImpl對象,因此組成流程定義的三個主要元素都可作為觀察者模式中的被觀察者來觀察,而這些對象本身就直接支持注冊各種Event,然后由Listener來監聽這些Event。 - 基于ExecutionImpl、Command模式和AtomicOperation實現的引擎調度
在jBPM4中用ExcutionImpl替掉了jBPM3中Token機制,流程的流轉,依賴于ExcutionImpl調用各個AtomicOperation原子操作(ExecuteActivity、MoveToParentActivity、TransitionTake、TransitionStartActivity、ExecuteEventListener、TransitionEndActivity)進行推進,而ExecutionImpl在各個實例對象之間進行轉移,詳細情況同樣參見《jBPM3與jBPM4實現對比》中的”流程啟動序列圖”和”流程推進序列圖”。(注:當時的那篇文章是基于jBPM4 alpha版本寫的,在正式版中有一些變化。) - 歷史庫的加入
作為任何一個正式運行的大數據量的軟件系統來講,沒有歷史庫的切分肯定只能當作玩具,而jBPM3沒有任何的處理,必須由開發人員自己來解決。在jBPM4中終于加入了這個功能,不過我認為目前Jbpm4的歷史庫設計還是存在一些問題的,例如,它是在活動(或任務)結束時,直接將數據歸入歷史庫,實際上我認為這是沒有必要的,我認為在整個流程實例結束時去做這個事情反而更好一些。其次,在將運行期的實例歸入歷史庫時,并不是將所有數據都進行了copy,這就造成了在歷史庫中丟掉了一些運行期的數據屬性。還有任務歷史庫中沒有針對task candidates參與模式的任務拾取時間的記錄導致無法做績效統計等。
2. 國內人工任務密集型流程的典型特點
中國目前在工作流領域主要的應用是人工工作流,也就是以人工任務密集型的工作流為主。當然隨著中國企業和公共組織的信息化發展越來越快,IT系統的積累和建設經驗也越來越豐富,因此以自動任務密集型為主的應用正在逐漸增多。但本文主要的還是講述人工任務密集型工作流的特色、需求、場景及實現。這種類型的流程應用,主要集中在以下領域如:電子政務,行政審批,企業協同辦公,電信、電力之工單,企業采購、合同、銷售等。
從功能需求上來說,這些人工任務密集型流程的典型特點主要有以下幾個方面:
1)用戶友好的流程定義工具,就是說由業務用戶自己對流程進行定義。其實這是一個偽命題,因為此處講的流程是可以run的,與業務系統有緊密的關系,完全地讓最終用戶來設計一個這樣的流程是不現實的(即使是不可以run的BPMN同樣也很困難,需要進行大量的培訓)。但是業務用戶是可以對已經建立好的流程進行改進的(呵呵,此處就是BPI的一個體現),因此提供一個基于WEB的,簡單易用的、用戶友好的流程設計器是非常有必要的。
2)表單自定義,就是說能有一個可高度定制的表單設計器,用戶可以隨時根據業務需求進行調整,或者新建表單,這個需求對于有“語義層”的form engine來講是可以實現的。那么除了表單自定義以外,當然還要能實現表單與流程任務的輕松綁定及表單權限的設定,使得不同環節的處理人能夠對表單的不同域有不同的讀寫權限。
3)靈活的臨時動態性需求,例如:任意回退、會簽(包括加、減簽,補簽)、撤銷(又叫回退)、自由流(又叫動態路由)。此處之所以叫做靈活的臨時動態性需求,就是因為這些需求,存在著很強的人為性因素(呵呵,此處才是真正的中國特色)。
3. 應用jBPM4解決國內的典型流程需求
3.1 用戶友好的流程定義工具
關于流程自定義,jBPM4本身提供了基于eclipse的plugin,可以讓開發人員來進行流程的建模,但是我們不可能讓一個業務流程管理員去下載使用Eclipse,因此我發起了一個基于jBPM4的開源工作流項目jBPM-side,上邊我已經提到了國內流程的典型需求,而這些需求直接用jBPM4來實現,需要很高的成本,因此將jBPM4進行本土化的改造封裝以滿足國內流程應用的需求,就是發起jBPM-side項目的目的。而上邊提到的所有典型需求,就是jBPM-side項目的特點。
目前jBPM-side正在全力開發基于flex的流程設計器,本項目的代碼在google托管地址如下:http://code.google.com/p/jbpmside/ ,此設計器是真正意義上的一個用戶友好的流程定義工具。我們初步的界面原型設計如下:
圖0 jBPM-side designer界面原型示意圖
另:jBPM4本身也已經開始BPMN的相關代碼開發了,建議也密切關注。
3.2 表單自定義
表單自定義的需求,應該來說在國內、國外都存在這種需求,我記得在jBPM的官方論壇里,Tom baeyens和其它人討論過電子表單的問題,但是現在在論壇中已經找不到了,在wiki上還可以看到Tom寫的文章:jBPM4andXForms,在這個文檔中,Tom baeyens認為可以用xform來作為Task form的一個實現,并給出了Orbeon和Chiba的鏈接,但同時也提到了他們會繼續調查freemarker和velocity這兩個模板引擎,并且說這件事情仍需要繼續討論,所以目前jBPM的團隊并沒有在表單自定義方面的計劃。jBPM4 的子項目GWT-console目前默認的表單實現采用了freemarker方案,但是freemarker僅僅是一個模板引擎框架,與真正的電子表單產品(例如infopath,一個完整的電子表單產品,包括表單設計器、表單引擎、數據存儲、事件引擎等)還相差甚遠。jBPM-side項目可能會基于Orbeon或Chiba進行表單引擎及設計器的本土化封裝,同時也提供商業電子表單產品的調用接口。
3.3 靈活的臨時動態性需求
3.3.1 回退
需求描述:
回退作為審批流來講是最常見的需求,對于審批流來說,每一個審批環節都有可能會有審批通過、不通過2種情況,而審批不通過時,一般是回退到上一個環節,但是在某些情況下,有可能跨環節回退,例如,在第5個審批環節,審批不通過時,直接回退到第2或第1個環節。而到底回退到哪個環節是可以讓用戶根據業務需求進行自定義的,并且在回退環節工作完成之后,其下一步的方向也可以讓用戶自定義。如,要是由第5個環節回退到第2個環節,那么當第2個環節重新修改業務數據并辦理完畢后,流程引擎可以設定是重新按照2-3-4-5的順序重新執行一遍,也可以設定由第2個節點返回給第5個節點,由第5個節點重新審批。
場景及jBPM4實現思路:
圖1 串行流程示意圖
場景1 串行流程: 在這個場景中,由于流程是串行的,沒有分支的情況,因此處理起來最簡單(如圖1所示)
場景1實現思路:
對于這個場景,在jBPM4中,最直接的方式,就是在需要回退的各個節點之間建立回退線(如圖5所示,如果需要從節點4回退到節點2,則直接在節點4之后加一個分支決策節點,連接兩個分支,一個是pass to 節點5,一個是reject to 節點2)。
對于節點2來講,在jBPM4中,其參與模式又分為4種:task-assignee(assignee user、assignee expression)、task candidates(candidate-groups、candidate-users)、task assignment handler、task swimlanes。
以上4種情況,在回退之后的處理,又分為2種情況,一種是,按照原來的路徑重新執行,即節點2—節點3—節點4,另一種是,節點2辦理完畢后,直接返回給節點4。對于第1種情況,不需要做處理。而對于第2種情況,由于在節點2和節點4之間并沒有一個轉移存在,因此jBPM4也沒有提供原生的支持。那么針對這種情況,筆者的解決思路是:通過動態創建跳轉來實現(具體實現方法,詳見3.3.4),實際上回退也可以用動態創建跳轉來實現,而就不用畫回退線了。
圖2 串行流程的回退實現
場景2 M選N分支流程: 對于這個場景,N的取值范圍為M>N>=1,假設回退前流程的執行路徑為節點1-節點2-節點4-節點5(見圖3),此時回退有兩種情況:
圖3 分支流程示意圖
場景2 實現思路:此場景與場景1不同的是,在回退之后繼續審批時,需要考慮分支節點的決策條件,在自動決策時要保證決策邏輯正確執行,在人工決策時,需要記錄原來的執行路徑(保證重走1-2-4-5)。
場景3 同步分裂、與匯聚流程(如圖4所示),回退前執行的路徑為節點1--節點2--(節點3、節點4)--節點5--節點6,此時回退有4種不同的情況要考慮:
圖4 同步分裂,與匯聚流程示意圖
場景3實現思路:此場景當流程由節點6回退到節點3,節點3辦理完畢后,重走路徑節點3-節點5-節點6時,在“與節點”的與運算邏輯就會無法執行,因為另一個與分支,節點 4并沒有新的實例產生,流程就會僵死此處。在jBPM4中,可以通過修改JoinActivity.java這個類中的protected boolean isComplete(List<executionimpl> joinedExecutions, Activity activity)這個方法,在方法中加入對此場景的處理代碼即可。
場景4 同步分裂、或匯聚流程(如圖5所示),回退前執行的路徑為節點1--節點2--(節點3、節點4)--節點5--節點6,此時回退有4種不同的情況要考慮:
圖5 同步分裂,或匯聚流程示意圖
場景4實現思路:此場景與場景3相比,因為是或匯聚,因此在實現上不需要做任何處理了。
場景5子流程: 就是流程嵌套的場景,在父流程中通過子流程節點啟動了子流程實例,此時回退時,就更復雜了,因為涉及到了不同的流程實例、還有在父子流程之間的數據傳遞。
場景5實現思路:子流程的回退,原則上是不支持的,因為涉及到不同的流程實例之間的回退,這個場景在jBPM4中實現起來異常的復雜,而且實際的業務場景也極少,因此在此不建議做這個實現。
小結:
綜合來講,回退本身在理論上來講有各種各樣的情況存在,再加上業務的回退(或者說業務邏輯補償?如果需要你就必須在流程的每個環節進行業務快照的備份,在回退時調用這個快照進行補償),此時回退可以說是整個流程體系中最復雜的情況了。但是在真實的業務場景中,有些情況可能是根本不會出現或者說很少出現的(畢竟理論不等于現實嘛)。因此技術人員一定要摒棄一個習慣,就是不要完全從理論和技術的角度考慮問題,一定要看用戶是否有這樣的需求,即便有了特定的需求,也首先要考慮的是能不能通過變通的方式處理,或者說服用戶放棄這個不合理的需求,最后實在沒辦法了,再去考慮技術的實現。
3.3.2 會簽
需求描述:
會簽在政府或企業來講都是必有的功能,尤其是審批流中。簡單來說,會簽是可以分為單步會簽(只有一個審批環節),及多步會簽(每一個子審批流有多個審批環節)的。
單步會簽:很簡單,就是在流程的某個環節需要由多個辦理人(多個不同部門的領導)共同辦理,或者簽署意見。這個場景就不用說了,在企業或政府的內部都很常見。
多步會簽(也叫并聯審批):其實就是一個單步的審批環節就變為了在部門內部一個比較復雜的審批流程,這個審批流程有多個審批環節。
加簽:在流程定義期已經定義好會簽范圍(例如某個崗位或部門),但是在運行期,會簽發起人發現對于某個個例需要新增會簽人或會簽單位,而且新增的會簽對象不在原來設定好的范圍內。此時由會簽發起人直接進行加簽操作。
減簽:同上,只是相反的操作而已。
補簽:會簽發起人已經將會簽任務發送給張、李、王三個人,而此時,張發現這個任務還需要孫來會簽,那么此時,可以由張直接發起一個給孫的補簽任務,而不必回退到會簽發起人那里。
會簽百分比:會簽發起人將任務發送給5個人辦理,而結果是只要有80%的會簽百分比即可算審批通過(也就是說只要有4個人審批通過就OK了)。
場景:
單步會簽:對于單步會簽的場景很簡單不在此描述了。
單步會簽的實現思路:可以對TaskService進行擴展開發,實現動態任務實例的創建,可參照TaskActivity這個類中的方法進行擴展,擴展之后再調用addTaskParticipatingUser()或addTaskParticipatingGroup()方法實現動態增加任務辦理人,此時即實現了單步會簽功能。
多步會簽場景一:審批環節相同。在企業內部的各個部門之間(例如,辦公室、采購部、財務部)進行并聯審批,每個部門中都需要多個審批環節,而這些部門的審批環節完全相同,只是每個審批環節的辦理人不同而已(例如在財務部,需要財務專員、財務經理、財務總監等審批;在辦公室需要辦公室科員、辦公室副主任、辦公室主任審批),因此可以公用一個子流程定義。
場景一的實現思路:最常見的方案是通過啟動一個子流程定義的多個子流程實例來實現多步會簽。這時,即便是對于會簽的部門數是未知的,需要動態決定,也可以輕松實現,只需要在運行期根據會簽部門數動態地創建同等數量的子流程實例就可以了。 但是不要高興的太早J,由于在jBPM4 中,流程的推進是依賴于ExecutionImpl來執行的,而對于每一個流程實例 ProcessInstance持有的ExecutionImpl實例也只有一個與之關聯的subProcessInstance,因此對于一個子流程節點SubProcessActivity來說也就只能有一個子流程實例與之關聯了,此時要想通過啟動一個子流程定義的多個子流程實例來實現多步會簽,實現方法與在jBPM3中實現多子流程實例類似(可以在網上搜到很多demo),就是結合Event-Listener機制和對Variable的使用,去創建多個子流程實例(注意的是在jBPM4中沒有ActionHandler了,取而代之的是基于觀察者模式的Event-Listener機制)。
多步會簽場景二: 審批環節不同。實際上與場景一相比,就是會簽部門的審批環節不同了,也就是說在企業內部的每個部門都要有自己的審批流程,其它與場景一是完全一致的。
場景二的實現思路:此場景,可以和場景一的實現相同,唯一不同的是由一個子流程定義的多個實例,變為了不同子流程定義的不同實例。
多步會簽場景三: 分布式審批。在政府部門,例如我們需要去政府的行政大廳去辦理新公司注冊,那么在行政大廳啟動一個新公司注冊的流程,在申請人提交完所有資料后,流程繼續向下執行,這時可能就需要工商局、公安局、地稅、國稅等多個委辦局進行內部的并聯審批,每個委辦局都需要在內部走一個復雜的審批流程,每個委辦局的流程審批完畢后,流程回到行政大廳的那個父流程中。此場景與場景二相比,其實就是企業內部的各個部門變為了不同的委辦局或子公司,此時的流程是分布式部署在各個委辦局或子公司的。
場景三的實現思路:由父流程執行到某個會簽節點時,通過 jms消息向各個會簽部門(注意這個會簽部門一般都是分布的,例如公安局、工商局、稅務局等)發送業務數據,而父流程在此等待會簽結果,而各個會簽部門都有自己的監聽器,在監聽到會簽請求時,在內部發起自己的審批流,內部審批完畢再發送業務數據給父流程,父流程接收到審批結果的業務數據后,流程繼續向下執行。
在jBPM4中實現起來就很簡單了,因為jBPM4提供了jms的消息、Event-Listener機制,而jBPM4本身也完全是基于觀察者模式進行設計的,此時通過在會簽節點上綁定特定的Listener,在Listener中向特定的目標發送jms消息(可參見MailListener的實現)。
小結
對于單步會簽的應用場景較多,在jBPM4中也提供了直接的支持。
對于多步會簽場景一,實際上這個場景在真實的企業中并不多見,因為大多數的需要會簽的業務都是只需要部門中的一個關鍵領導審批就可以了,也就是單步會簽的場景。當然如果在某個特定的企業中,這種情景很多,為了流程管理員使用方便,那么對jBPM4的代碼做一定的修改也是可以的。
對于多步會簽場景三,實際上,由于各個部門(公安局、工商局、稅務局)都是分布的,采用的工作流產品也是不同的,即便是同一個公司的產品,也是分布式部署的,因此在這個場景中,是不需要用subprocess或subProcessActivity這些概念的。因為此時的并聯審批本質上是兩個相同等級的流程之間的通信而已。
3.3.3 撤銷
需求描述:
任務在發送給下一個辦理人之后,發現任務發送錯誤了,此時在下一個辦理人還沒有辦理之前,可以撤回當前任務,而重新選擇其它人進行辦理。
場景:
撤銷的場景與回退的場景很類似,雖然有很多的場景,但是各個場景的處理情況是一樣的,因此在此只給出最簡單的一個場景,如下圖6所示:
圖6 串行流程示意圖
節點2的處理人(假設是張三),辦理完畢之后,將任務提交,此時任務到達了節點3(假設李四辦理),這時李四就會收到一個待辦任務,在李四還沒有辦理之前,張三突然發現,有一個業務數據填寫錯誤,或者粘貼的附件錯誤,這時張三需要將發送給李四的任務撤銷(也叫收回),重新更正數據后或修改粘貼的附件后再發送給李四審批。還有一種情況是,假設節點3的辦理人有2個人(李四和王五),那么張三需要在運行期根據業務特性手動地選擇任務是提交給李四還是王五,但是由于李四的誤操作,把本來應該發給王五的辦理任務錯發送給了李四,此時,在李四辦理之前,張三也可以將發送給李四的任務撤銷(或收回),然后重新發送給王五。
jBPM4實現:
在jBPM4中實現撤銷,雖然場景有很多,但是各個場景的處理是一樣的,也就是在撤銷時,首先刪除需要撤銷的任務實例及其與此任務實例相關的所有工作流實例。在jBPM4提供了級聯刪除任務實例的相關方法,如下:
TaskServiceImpl.javapublic void deleteTaskCascade(String taskId) {commandService.execute(new DeleteTaskCmd(taskId, true));}其次修改當前任務實例的狀態,即將張三的已經辦理完畢的節點2對應的TaskInstance的狀態更改為待辦狀態:
(Task.STATE_OPEN)task.setState(ask.STATE_OPEN);taskService.saveTask(task);小結:
撤銷的需求在審批流中也是最常見的業務需求,畢竟人都有犯錯的時候嘛,而且一般的軟件都有Undo功能。但是對于jBPM4中的fork-join,sub-process都需要把撤銷任務的相關實例都刪除。
3.3.4 自由流(動態路由)
需求描述:
針對于特定的業務實例,在原本沒有轉移關系的環節之間進行特定的跳轉,例如在一個串行的流程中(1-2-3-4-5),節點2與節點5之間是沒有任何轉移存在的,但是針對于某個運行期的特定業務實例,要求,審批環節直接從節點2跳轉到節點5(而略過了節點3和節點4)。
場景:
圖7 串行流程示意圖
jBPM4實現:
圖8 動態路由實現示意圖
如圖8所示,在節點2 和節點4之間由程序動態地創建一個轉移(transition),并設定為優先級最高,那么在執行takeTransition()方法時,按照優先級優先執行動態的轉移,然后對外暴露一個jumpTransition(String destinationActivityName)方法給客戶端。在jBPM4中,可按照如下步驟實現:
小結:
jBPM4中的執行動作都是基于Command模式來實現的,因此我們在擴展開發自己的跳轉動作時,就可以做到對jBPM4本身的代碼不做侵入修改而實現。
4. 總結
jBPM4做為目前應用最廣泛的開源工作流產品,有著很好的架構及擴展性,但是由于國外的流程應用與國內的應用存在著一些不同,因此要想讓jBPM4更好地滿足國內的流程應用的需求,就需要做一定的定制開發。而其最大的問題就是沒有一個可供業務流程管理員用來進行流程改進的設計器,因此從這一點上,也大大阻礙了其在國內的應用。而本文針對國內的流程應用的一些典型特點進行較詳細的分析,并給出基于jBPM4的大概的解決思路和辦法,但是并沒有給出很詳細的完全可以run的code,但是筆者認為這些不是最重要的,最重要的是解決問題的思路。而具體的解決方案的code,請讀者關注jBPM-side,因為是一個開源項目,因此在此項目中,將會看到完全可以run的code。
總結
以上是生活随笔為你收集整理的应用jBPM4解决中国特色的流程需求 (看过之后,强烈推荐)的全部內容,希望文章能夠幫你解決所遇到的問題。