大牛的傑做,贊一個html
轉自:NetBPM工做流的架構設計及實現淺析web
讀前的話:因爲本文涉及內容頗多,如有地方讀來不很明白,建議先跳過,總體上有個認識後,再回過頭來理解。做者認識有限,如有錯誤,歡迎斧正:)原文地址: NetBPM工做流的架構設計及實現淺析(轉載請保留)數據庫
NetBPM由一系列的組件構成,每個組件都實現一個核心接口(採用Facade Pattern)。不一樣組件各自負責的核心功能根據WfMC規範而來。
NetBPM接口圖:apache
下面咱們逐步介紹NetBPM的各個組件,下面是NetBpm組件結構圖:編程
該組件實現核心接口IDefinitionSessionLocal,用來解析、加載流程定義壓縮包,並將其保存到數據庫中。此外,它還提供獲取某個流程定義,獲取全部有效流程定義列表等和流程定義相關的方法。架構
該組件實現了核心接口IExecutionSessionLocal,它是NetBPM引擎推進核心,如前面如述,它主要實現2個方法:開始一個流程實例(Start ProcessInstance)和執行一個活動(Perform Activity)。另外,它還提供獲取用戶任務列表,取消流程實例等輔助流程運轉的方法。框架
該組件實現接口IOrganisationSessionLocal,它把全部的組織架構信息都彙集在一塊兒,包括Users、Groups和Memberships。運轉組件在爲activitie-state指定執行者時,須要有關user和group的信息。這些信息將以只讀模式由組織架構組件向運轉組件提供。下面是NetBPM默認的組織架構組織數據模型。在此基礎上,咱們能夠很方便的實現自定義的適合實際項目需求的組織架構組件,以和咱們的用戶數據庫或者是LDAP系統相關聯。ide
NOTE:NetBPM源碼中實現的只是一個簡單的組織架構模型,但它提供了一種思考方向,咱們能夠很方便在此基礎上進行擴展來實現知足切實需求的自定義組織架構組件:)工具
該組件實現接口ILogSessionLocal,用來記錄工做流引擎的操做痕跡,象屬性值的更新(如用戶提交的表單被上級打回從新填寫,那麼就會出現屢次表單數據,這就是一種屬性更新),委託類的調用狀況等都會被記錄下來保存到數據庫中。單元測試
該組件實現接口ISchedulerSessionLocal,在現實的業務流程中,咱們常常會遇到須要定時觸發某個任務的需求,任務調度組件正是做用於此。引擎或者是第三方把須要在某個時刻執行的任務信息(包括任務執行環境、執行時間等)封裝成Job保存到數據庫中。任務調度組件將按照指定的時間間隔不停的掃描任務表,根據執行時間對比來執行定時到了的Job。
該組件用來對流程定義,流程實例執行狀況等進行監控。(源碼待完善)下面是NetBpm核心項目在Visual 該組件用來對流程定義,流程實例執行狀況等進行監控。(源碼待完善)
下面是NetBPM核心項目在Visual Studio解決方案中的源碼結構圖,全部組件都包含在Workflow文件夾下,每個文件夾分別對應實現了一個核心組件。
flow不知道翻譯爲何好,在JBPM中叫作Token,翻譯爲令牌,這裏咱們就叫作flow吧。它表明activity-states(活動節點,見nPdl)的一個「thread of execution」,至關因而一次流程實例執行過程當中在流程定義模板中的令牌(還真難描述清楚,看下面一塊兒理解:))。前面說了,一個流程實例表明一個流程定義的一次執行。以下圖所示,流程實例的狀態能夠當作是一顆flows樹。
當開始一個流程實例後,在start-state(開始節點,見nPdl,start-state實際上能夠看作是一種特殊的activity-state)引擎將自動產生一個名爲root的flow。flow中包含了該流程實例的相關信息,如屬性值、流程定義信息、flow所在activity-state的執行者等。root flow在遇到fork(分散節點,見nPdl)以前,將更新其帶有的實時信息(如執行者、屬性值等),這些實時信息隨着流程的運轉而變化。遇到fork後,根據ForkHandler委託類,root flow將分散成若干(>1個)forked flow(咱們能夠把root flow稱爲這些forked flow的父flow)。如果分散爲多個,則此時forked flow將並行運行,父flow則暫時退隱,只至到join(匯聚節點,見nPdl)匯聚,引擎將根據join定義的JoinHandler委託類來肯定激活父flow的機制。
NOTE:關於fork和join機制,請參考nPdl fork、join小節一塊兒理解。
attribute用來表示流程實例中的變量。一個attribute-instance(屬性實例,也就是屬性值)表明一次流程實例執行過程當中對應屬性的實例。屬性通常有幾種,一種是activity-state(包括start-state)須要用戶或者第三方來填寫(更新)的屬性(通常對應用戶Web界面表單上要填寫的值),一種是角色對應的屬性,還有一些用做標識屬性(用來存儲某些信息以方便後面的節點運用這些信息處理邏輯判斷)。
由於圖片太大,關於繼承IHandlerContext的接口關係圖查看點擊這裏
ExecutionContext(ExecutionContextImpl類型的對象,咱們暫且翻譯爲運行時上下文環境:)) 包含了引擎在運行時和流程實例相關的全部有用信息(上文中提到的flowcontext就是一種ExecutionContext),它在委託類(包括流程定義壓縮包中程序集中定義的委託類)和流程引擎之間創建起了相互聯繫的渠道,這是很是關鍵的。如上面ExectutionContext 類圖所示,ExecutionContextImpl實現了下面這些接口:IAssignmentContext、IDecisionContext、IForkContext、IActionContext、IJoinContext、IProcessInvocationContext、ITaskContext,這些接口都是爲匹配特定的委託類而設計,它們規範了一種特定的上下文環境,如IActionContext匹配action類型委託類,IDecisionContext匹配DecisionHandler類型委託類等,而ExectutionContext是全部這些特殊的運行時上下文環境的一個綜合。當引擎在運轉組件把ExectutionContext做爲參數傳送到具體類型的委託類時(關鍵:這就是委託類和流程引擎創建聯繫的方式),ExecutionContext對象將「拆箱」成爲特殊的Context,如:把ExecutionContext對象傳給action類型的委託類Run()方法時,ExecutionContext對象將拆箱爲ActionContext對象以限制其可以調用的方法。
如「繼承自IHandlerContext的接口」圖中所示,這些接口都繼承了同一個接口IHandlerContext。IHandlerContext是一個規範了最基本的委託類處理上下文環境的接口,實現該接口的繼承幾口也就都要實現IHandlerContext中定義的方法,固然每一種繼承它的特定接口又均可以具備其特定的方法。咱們先看公共接口IHanlderContext類圖:如上IHandlerContext接口圖所示,這些接口都繼承了同一個接口IHandlerContext。IHandlerContext是一個規範了最基本的委託類處理上下文環境的接口,實現該接口繼承接口的類也就都實現了IHandlerContext中定義的方法。固然,每一種繼承它的特定接口又均可以具備其特定的方法。咱們先看公共接口IHanlderContext類圖:
大多數的方法,咱們從方法名稱就能夠看出其具體做用了,這裏重點介紹下GetAttribute()方法和GetConfiguration()方法,這是咱們在寫委託類實現時,要常常用到的2個方法。GetAttribute()用來獲取流程實例中的屬性值,包括流程前面處理者產生的屬性值(如用戶填寫表單的值)和前面處理引擎事件中設置的表示屬性值(注:IActionHandler具備SetAttribute()方法,該方法常常用來標識屬性值,供後面程序邏輯用)等。而GetConfiguration()用來獲取流程定義中設置的parameter(參數,請nPdlparameter小節)。
下面再來看幾種典型的特定上下文環境接口:
在前面咱們一直提到委託類,那麼委託類究竟是什麼呢?這裏委託的概念指的不是.NET Framework中delegate,這裏能夠理解它爲「委託、代爲處理」這樣的概念就好。
NetBPM被設計成通用的流程處理引擎,NetBPM核心執行引擎只負責處理最基本的業務流程邏輯,全部不定的邏輯都被委託給一系列的接口,這些接口稱做Delegation Interfaces(委託接口),而實現這些接口的類就是委託類。流程定義約定在什麼場合使用什麼委託類型,引擎和委託類如何關聯也在流程定義中完成。
爲了達到最大的可擴展性,流程開發者在流程定義時能夠選擇下面任意一種委託類實現方式:
正是方式2這種形式給NetBPM帶來了極大的靈活性,把只適合於某個特定流程的的程序邏輯(這些每每佔了大多數)以.NET程序集的形式定義在流程定義壓縮包中,NetBpm經過流程定義組件將其解析並保存至數據庫。當引擎運轉流程須要調用委託類時,引擎利用反射技術實例化出委託類對象,而後利用上文介紹的運行時上下時環境(ExecutionContext)創建起委託類和引擎之間的交互渠道,這真是一個使人興奮的設計:)
下面是NetBpm中的委託類型(建議和ExecutionContext一節一塊兒理解):
................///////////////////////////.............是否要添加委託類的例子
包含在一個流程定義壓縮包中的信息叫作流程定義。NetBpm中,流程是由字段name來區分的,也就是說引擎根據流程的name來判斷兩個流程是否相等。在流程定義包中不能指定版本,當一個流程定義被引擎加載後,NetBpm將檢查是否有該流程定義的舊版本。若是有,NetBpm將自動設置該新加載進來的流程版本爲全部存在的舊版本流程定義中最高版本數目基礎上加1。
當調用運轉組件獲取流程定義列表方法時,只能獲取到每一個流程的最高版本流程定義。這樣作保證了用戶老是從最新版本的流程定義開始一個流程實例。當新的流程版本加載到NetBpm時,全部正在運行的舊版本的流程實例將保持在原來流程定義方式下運行。
關於版本的另一個方面是委託類。不一樣版本流程定義的委託類不是共享的,也就是說每一個流程在執行時只會「看到」它本身流程定義的委託類。
NetBpm做爲一個集成平臺,當流程運行時,確定會依賴公司不少其餘的IT資源,一旦這些依賴致使流程執行時出現錯誤,NetBpm提供了3種解決機制:
執行回滾機制中,流程實例將會被回滾到執行activity以前的狀態。若是是對NetBpm 調用Eecution Interface時發生流程錯誤,全部的流過的transition(邊)都會執行回滾。
關於流程定義的詳細狀況,參見nPdl。
NetBpm中用到的框架、組件、工具比較多,它們大都是優秀的開源項目。如Castle,NHibernate,Log4Net, NVelocity,NUnit,NAnt等,不要被這些框架嚇倒,實際上,它們僅僅只是「框架」而已:)
NetBpm使用了Castle框架,主要用它來實現IOC(控制反轉或者說依賴注入),以依賴注入的方式加載核心組件,如DBClassLoader,流程定義組件,運行組件,日誌組件,組織架構組件,任務調度組件等。在Web程序啓動的時候,根據配置文件,全部的核心組件都將註冊到Caslte IOC容器中,之後當須要使用某個組件的時候,只需利用系統提供的ServiceLocator(服務加載工具類)從容器中獲取實例便可。另外,在任務調度組件中也有用到Castle的Startable Facility(注:你們把facility理解爲注入性質的,對Castle IOC內核容器的功能擴充組件。Castle自己自帶實現了一些faciltiy,開發者也能夠自定義facility),該facitlity主要用來自動運行程序(這裏用來自動間隔掃描任務表,進行任務調度)。
Castle是.NET平臺下一個功能強大的優秀開源框架,關於Castle的更多信息,請看Castle官方網站。另外TerryLee的博客中關於Castle的中文資源也很豐富。
NetBpm中NHibernate組件是做爲Castle的一個facility存在的,它用來實現NetBpm數據持久層, 並方便的實現了事務支持。關於NHibernate的更多信息,請看NHibernate官方網站,關於NHibernate做爲Castle的facility相關請看這裏。
你們在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實現Web部分顯然是更好的選擇:)。關於MonoRail的更多信息,請看這裏。
log4net你們必定不陌生了,NetBpm使用它來記錄系統日誌,關於log4net的更多信息,請看Log4Net官方網站,網上中文資源也很豐富.
單元測試工具NUnit一直是你們用來單元測試的利器。 NetBPM源碼中已經建有幾個測試工程。關於NUnit的更多信息,請看NUnit官方網站。
注:移植到.NET Framework 2.0下,可能要更改其版本。
NetBPM的設計無疑是巧妙的,可是現階段的它顯然還不是一個完美的工做流引擎,缺少如JBOSS這樣的強大後盾做支持,中途又趕上強敵WF,NetBPM遠沒有其兄弟JBPM風光,更新沒有它快(JBPM已經出3.0版本了),獲取的支持也少量多, 可是.NET平臺下能有這樣一個優秀的開源工做流項目是十分難得的,若是您正在WF中苦苦掙扎,也許,開源的NetBPM將帶給您一個驚喜:)
待寫:NetBPM工做流nPdl詳解,一個NetBPM現實生活中請假審批示例