NetBPM工作流的架構設計及實現(xiàn)淺析Made by LuBen:2007年08月01日 |
目錄組織架構組件(Oorganization Component) 引擎運行時上下文環(huán)境(Execution Context) 讀前的話:由于本文涉及內容頗多,若有地方讀來不很明白,建議先跳過,整體上有個認識后,再回過頭來理解。作者認識有限,若有錯誤,歡迎斧正:)原文地址: NetBPM工作流的架構設計及實現(xiàn)淺析(轉載請保留) NetBPM組件接口 NetBPM由一系列的組件構成,每一個組件都實現(xiàn)一個核心接口(采用Facade Pattern)。不同組件各自負責的核心功能根據(jù)WfMC規(guī)范而來。
下面我們逐步介紹NetBPM的各個組件,下面是NetBpm組件結構圖: 定義組件(Definition Component)該組件實現(xiàn)核心接口IDefinitionSessionLocal,用來解析、加載流程定義壓縮包,并將其保存到數(shù)據(jù)庫中。此外,它還提供獲取某個流程定義,獲取所有有效流程定義列表等和流程定義相關的方法。 運轉組件(Execution Component)該組件實現(xiàn)了核心接口IExecutionSessionLocal,它是NetBPM引擎推動核心,如前面如述,它主要實現(xiàn)2個方法:開始一個流程實例(Start ProcessInstance)和執(zhí)行一個活動(Perform Activity)。另外,它還提供獲取用戶任務列表,取消流程實例等輔助流程運轉的方法。 組織架構組件(Organization Component)該組件實現(xiàn)接口IOrganisationSessionLocal,它把所有的組織架構信息都聚集在一起,包括Users、Groups和Memberships。運轉組件在為activitie-state指定執(zhí)行者時,需要有關user和group的信息。這些信息將以只讀模式由組織架構組件向運轉組件提供。下面是NetBPM默認的組織架構組織數(shù)據(jù)模型。在此基礎上,我們可以很方便的實現(xiàn)自定義的適合實際項目需求的組織架構組件,以和我們的用戶數(shù)據(jù)庫或者是LDAP系統(tǒng)相關聯(lián)。 NOTE:NetBPM源碼中實現(xiàn)的只是一個簡單的組織架構模型,但它提供了一種思考方向,我們可以很方便在此基礎上進行擴展來實現(xiàn)滿足切實需求的自定義組織架構組件:) 日志組件(Log Component)該組件實現(xiàn)接口ILogSessionLocal,用來記錄工作流引擎的操作痕跡,象屬性值的更新(如用戶提交的表單被上級打回重新填寫,那么就會出現(xiàn)多次表單數(shù)據(jù),這就是一種屬性更新),委托類的調用情況等都會被記錄下來保存到數(shù)據(jù)庫中。 任務調度組件(scheduler component)該組件實現(xiàn)接口ISchedulerSessionLocal,在現(xiàn)實的業(yè)務流程中,我們經(jīng)常會遇到需要定時觸發(fā)某個任務的需求,任務調度組件正是作用于此。引擎或者是第三方把需要在某個時刻執(zhí)行的任務信息(包括任務執(zhí)行環(huán)境、執(zhí)行時間等)封裝成Job保存到數(shù)據(jù)庫中。任務調度組件將按照指定的時間間隔不停的掃描任務表,根據(jù)執(zhí)行時間對比來執(zhí)行定時到了的Job。 管理監(jiān)控組件(Admin Component)該組件用來對流程定義,流程實例執(zhí)行情況等進行監(jiān)控。(源碼待完善)下面是NetBpm核心項目在Visual 該組件用來對流程定義,流程實例執(zhí)行情況等進行監(jiān)控。(源碼待完善) 下面是NetBPM核心項目在Visual Studio解決方案中的源碼結構圖,所有組件都包含在Workflow文件夾下,每一個文件夾分別對應實現(xiàn)了一個核心組件。 NetBpm中的幾個重要概念flow flow不知道翻譯為什么好,在JBPM中叫做Token,翻譯為令牌,這里我們就叫做flow吧。它代表activity-states(活動節(jié)點,見nPdl)的一個“thread of execution”,相當于是一次流程實例執(zhí)行過程中在流程定義模板中的令牌(還真難描述清楚,看下面一起理解:))。前面說了,一個流程實例代表一個流程定義的一次執(zhí)行。如下圖所示,流程實例的狀態(tài)可以看成是一顆flows樹。 當開始一個流程實例后,在start-state(開始節(jié)點,見nPdl,start-state實際上可以看做是一種特殊的activity-state)引擎將自動產(chǎn)生一個名為root的flow。flow中包含了該流程實例的相關信息,如屬性值、流程定義信息、flow所在activity-state的執(zhí)行者等。root flow在遇到fork(分散節(jié)點,見nPdl)之前,將更新其帶有的實時信息(如執(zhí)行者、屬性值等),這些實時信息隨著流程的運轉而變化。遇到fork后,根據(jù)ForkHandler委托類,root flow將分散成若干(>1個)forked flow(我們可以把root flow稱為這些forked flow的父flow)。若是分散為多個,則此時forked flow將并行運行,父flow則暫時退隱,只至到join(匯聚節(jié)點,見nPdl)匯聚,引擎將根據(jù)join定義的JoinHandler委托類來確定激活父flow的機制。 NOTE:關于fork和join機制,請參考nPdl fork、join小節(jié)一起理解。 attributes(屬性)attribute用來表示流程實例中的變量。一個attribute-instance(屬性實例,也就是屬性值)代表一次流程實例執(zhí)行過程中對應屬性的實例。屬性一般有幾種,一種是activity-state(包括start-state)需要用戶或者第三方來填寫(更新)的屬性(一般對應用戶Web界面表單上要填寫的值),一種是角色對應的屬性,還有一些用作標識屬性(用來存儲某些信息以方便后面的節(jié)點運用這些信息處理邏輯判斷)。
引擎運行時上下文環(huán)境(Execution Context) 因為圖片太大,關于繼承IHandlerContext的接口關系圖查看點擊這里 ExecutionContext(ExecutionContextImpl類型的對象,我們暫且翻譯為運行時上下文環(huán)境:)) 包含了引擎在運行時和流程實例相關的所有有用信息(上文中提到的flowcontext就是一種ExecutionContext),它在委托類(包括流程定義壓縮包中程序集中定義的委托類)和流程引擎之間建立起了相互聯(lián)系的渠道,這是非常關鍵的。如上面ExectutionContext 類圖所示,ExecutionContextImpl實現(xiàn)了下面這些接口:IAssignmentContext、IDecisionContext、IForkContext、IActionContext、IJoinContext、IProcessInvocationContext、ITaskContext,這些接口都是為匹配特定的委托類而設計,它們規(guī)范了一種特定的上下文環(huán)境,如IActionContext匹配action類型委托類,IDecisionContext匹配DecisionHandler類型委托類等,而ExectutionContext是所有這些特殊的運行時上下文環(huán)境的一個綜合。當引擎在運轉組件把ExectutionContext作為參數(shù)傳送到具體類型的委托類時(關鍵:這就是委托類和流程引擎建立聯(lián)系的方式),ExecutionContext對象將“拆箱”成為特殊的Context,如:把ExecutionContext對象傳給action類型的委托類Run()方法時,ExecutionContext對象將拆箱為ActionContext對象以限制其能夠調用的方法。 如“繼承自IHandlerContext的接口”圖中所示,這些接口都繼承了同一個接口IHandlerContext。IHandlerContext是一個規(guī)范了最基本的委托類處理上下文環(huán)境的接口,實現(xiàn)該接口的繼承幾口也就都要實現(xiàn)IHandlerContext中定義的方法,當然每一種繼承它的特定接口又都可以具有其特定的方法。我們先看公共接口IHanlderContext類圖:如上IHandlerContext接口圖所示,這些接口都繼承了同一個接口IHandlerContext。IHandlerContext是一個規(guī)范了最基本的委托類處理上下文環(huán)境的接口,實現(xiàn)該接口繼承接口的類也就都實現(xiàn)了IHandlerContext中定義的方法。當然,每一種繼承它的特定接口又都可以具有其特定的方法。我們先看公共接口IHanlderContext類圖: 大多數(shù)的方法,我們從方法名稱就可以看出其具體作用了,這里重點介紹下GetAttribute()方法和GetConfiguration()方法,這是我們在寫委托類實現(xiàn)時,要經(jīng)常用到的2個方法。GetAttribute()用來獲取流程實例中的屬性值,包括流程前面處理者產(chǎn)生的屬性值(如用戶填寫表單的值)和前面處理引擎事件中設置的表示屬性值(注:IActionHandler具有SetAttribute()方法,該方法經(jīng)常用來標識屬性值,供后面程序邏輯用)等。而GetConfiguration()用來獲取流程定義中設置的parameter(參數(shù),請nPdlparameter小節(jié))。 下面再來看幾種典型的特定上下文環(huán)境接口:
委托類在前面我們一直提到委托類,那么委托類到底是什么呢?這里委托的概念指的不是.NET Framework中delegate,這里可以理解它為“委托、代為處理”這樣的概念就好。 NetBPM被設計成通用的流程處理引擎,NetBPM核心執(zhí)行引擎只負責處理最基本的業(yè)務流程邏輯,所有不定的邏輯都被委托給一系列的接口,這些接口稱作Delegation Interfaces(委托接口),而實現(xiàn)這些接口的類就是委托類。流程定義約定在什么場合使用什么委托類型,引擎和委托類如何關聯(lián)也在流程定義中完成。 為了達到最大的可擴展性,流程開發(fā)者在流程定義時可以選擇下面任意一種委托類實現(xiàn)方式:
正是方式2這種形式給NetBPM帶來了極大的靈活性,把只適合于某個特定流程的的程序邏輯(這些往往占了大多數(shù))以.NET程序集的形式定義在流程定義壓縮包中,NetBpm通過流程定義組件將其解析并保存至數(shù)據(jù)庫。當引擎運轉流程需要調用委托類時,引擎利用反射技術實例化出委托類對象,然后利用上文介紹的運行時上下時環(huán)境(ExecutionContext)建立起委托類和引擎之間的交互渠道,這真是一個令人興奮的設計:) 下面是NetBpm中的委托類型(建議和ExecutionContext一節(jié)一起理解):
................///////////////////////////.............是否要添加委托類的例子 流程定義版本問題流程定義的名稱與版本包含在一個流程定義壓縮包中的信息叫做流程定義。NetBpm中,流程是由字段name來區(qū)分的,也就是說引擎根據(jù)流程的name來判斷兩個流程是否相等。在流程定義包中不能指定版本,當一個流程定義被引擎加載后,NetBpm將檢查是否有該流程定義的舊版本。如果有,NetBpm將自動設置該新加載進來的流程版本為所有存在的舊版本流程定義中最高版本數(shù)目基礎上加1。 流程執(zhí)行與版本當調用運轉組件獲取流程定義列表方法時,只能獲取到每個流程的最高版本流程定義。這樣做保證了用戶總是從最新版本的流程定義開始一個流程實例。當新的流程版本加載到NetBpm時,所有正在運行的舊版本的流程實例將保持在原來流程定義方式下運行。 委托類與版本 關于版本的另外一個方面是委托類。不同版本流程定義的委托類不是共享的,也就是說每個流程在執(zhí)行時只會“看到”它自己流程定義的委托類。 NetBpm作為一個集成平臺,當流程運行時,肯定會依賴公司很多其他的IT資源,一旦這些依賴導致流程執(zhí)行時出現(xiàn)錯誤,NetBpm提供了3種解決機制:
執(zhí)行回滾機制中,流程實例將會被回滾到執(zhí)行activity之前的狀態(tài)。如果是對NetBpm 調用Eecution Interface時發(fā)生流程錯誤,所有的流過的transition(邊)都會執(zhí)行回滾。 流程定義元素類圖 關于流程定義的詳細情況,參見nPdl。
NetBpm中使用的框架或組件NetBpm中用到的框架、組件、工具比較多,它們大都是優(yōu)秀的開源項目。如Castle,NHibernate,Log4Net, NVelocity,NUnit,NAnt等,不要被這些框架嚇倒,實際上,它們僅僅只是“框架”而已:) IOC容器――CastleNetBpm使用了Castle框架,主要用它來實現(xiàn)IOC(控制反轉或者說依賴注入),以依賴注入的方式加載核心組件,如DBClassLoader,流程定義組件,運行組件,日志組件,組織架構組件,任務調度組件等。在Web程序啟動的時候,根據(jù)配置文件,所有的核心組件都將注冊到Caslte IOC容器中,以后當需要使用某個組件的時候,只需利用系統(tǒng)提供的ServiceLocator(服務加載工具類)從容器中獲取實例即可。另外,在任務調度組件中也有用到Castle的Startable Facility(注:大家把facility理解為注入性質的,對Castle IOC內核容器的功能擴充組件。Castle本身自帶實現(xiàn)了一些faciltiy,開發(fā)者也可以自定義facility),該facitlity主要用來自動運行程序(這里用來自動間隔掃描任務表,進行任務調度)。 Castle是.NET平臺下一個功能強大的優(yōu)秀開源框架,關于Castle的更多信息,請看Castle官方網(wǎng)站。另外TerryLee的博客中關于Castle的中文資源也很豐富。 數(shù)據(jù)持久層―― NHibernateNetBpm中NHibernate組件是作為Castle的一個facility存在的,它用來實現(xiàn)NetBpm數(shù)據(jù)持久層, 并方便的實現(xiàn)了事務支持。關于NHibernate的更多信息,請看NHibernate官方網(wǎng)站,關于NHibernate作為Castle的facility相關請看這里。 示例web層――MonoRail大家在Demo演示體驗的時候,一定很奇怪,沒有看到熟悉的.aspx頁面,而是.rails頁面,為什么呢?答案就是NetBPM的Web層采用的是MonoRail框架,而不是我們熟悉ASP.NET框架。MonoRail是Caslte框架下針對web層編程的一個子框架,它從Ruby Rails獲取靈感而來,采用架構清晰分工明確的MVC模式。NetBPM采用的使用NVelocity作為頁面解析引擎的MonoRail,它只是對NetBPM核心API的一個Web界面演示示例,用來告訴我們該怎樣從Web層調用NetBpm API。所以,雖然MonoRail有其獨到之處,但是在其被普及并有好用工具支持之前,我們只需簡單了解下它的運行機制,用以熟悉web層如何利用NetBpm API,不需要了解它太多。用我們熟悉的ASP.NET實現(xiàn)Web部分顯然是更好的選擇:)。關于MonoRail的更多信息,請看這里。 系統(tǒng)日志 ――Log4Netlog4net大家一定不陌生了,NetBpm使用它來記錄系統(tǒng)日志,關于log4net的更多信息,請看Log4Net官方網(wǎng)站,網(wǎng)上中文資源也很豐富. 單元測試工具――NUnit單元測試工具NUnit一直是大家用來單元測試的利器。 NetBPM源碼中已經(jīng)建有幾個測試工程。關于NUnit的更多信息,請看NUnit官方網(wǎng)站。 注:移植到.NET Framework 2.0下,可能要更改其版本。 NetBPM的設計無疑是巧妙的,但是現(xiàn)階段的它顯然還不是一個完美的工作流引擎,缺乏如JBOSS這樣的強大后盾作支持,中途又遇上強敵WF,NetBPM遠沒有其兄弟JBPM風光,更新沒有它快(JBPM已經(jīng)出3.0版本了),獲取的支持也少許多, 但是.NET平臺下能有這樣一個優(yōu)秀的開源工作流項目是十分可貴的,如果您正在WF中苦苦掙扎,也許,開源的NetBPM將帶給您一個驚喜:) 待寫:NetBPM工作流nPdl詳解,一個NetBPM現(xiàn)實生活中請假審批示例 |
posted on 2007-08-04 13:37 LuBen 閱讀(663) 評論(0) 編輯 收藏 引用 網(wǎng)摘 所屬分類: WorkFlow & NetBpm