提到工作流很多人就會想到OA,的確OA就是典型的工作流的應用,但是工作流并不僅僅局限于OA,工作流應該算是基礎框架軟件,主要用于流程的重組和優化,它有廣闊的應用領域。在java下有很多優秀的開源工作流可以選擇比如activit5、jpbm4等,在.net下卻幾乎找不到令人滿意的工作流引擎可用。當然不是說.net下沒有開源的只是有些國產開源的但看了代碼后就一點興趣都沒有了,且不說代碼質量如何,還引入了一大堆的東西,想在項目中應用也是非常困難。鑒于此我還是決定自己開發一款.NET微型工作流引擎。
為什么叫微型工作流引擎?就是超輕量級,以方便在項目中輕便的使用,比如只有一個類庫dll,大小也就幾百k到1M左右,不過我們要先回過頭來看看工作流系統,它實在是太大了,它應該包括: 1、工作流引擎 2、工作流設計器 3、工作流管理系統 4、表單設計器
目前來說的我只實現了核心引擎,流程定義也只能先在xml中編輯然后讀取到引擎中或者直接定義到數據庫中,但整個流程是能夠正常流轉。至于流程設計器、表單設計器、工作流管理系統這個我有精力了再慢慢開發。這里我完成的只是很小的一塊,但是是工作流的核心,可以很方便的嵌入到業務系統中應用。
引擎主要提供了對于工作流定義的解析以及流程流轉的支持。工作流定義文件描述了業務的交互邏輯,工作流引擎通過解析工作流定義文件按照業務的交互邏輯進行業務的流轉,工作流引擎通常通過參考某種模型來進行設計,通過調度算法來進行流程的流轉(流程的啟動、終止、掛起、恢復等),通過各種環節調度算法來實現對于環節的流轉(環節的合并、分叉、選擇、條件性的選擇等)。
1、從概念開始解釋估計大家都會看不下去了。我們先拿一個簡單實例來看看,新建一個項目,引用我的工作流引擎類庫(Chitu.Bpm.dll,取名為赤兔)。 在項目啟動時配置流程引擎(Global.asax.cs中),如下:
//初始化流程引擎BpmConfiguration .Instance() .Config(@"C:/Configration/BpmConfig.xml") .Start();
在項目中使用時,比如新建流程定義:
//取得工作流上下文var bpm = new BpmContext() .UseTransaction(true) .SetActor("蕭秦");//新增流程定義bpm.New啟動流程:
//啟動流程var process = bpm.NewProcessIntance("請假流程ID", "蕭秦(業務ID)"); //創建流程實例process.SetVariable("流程變量1", "值1"); //設置流程變量process.Start();人工任務節點轉交下一步:
//任務完成var task = bpm.LoadTaskInstance("任務ID");task.SetVariable("任務變量2", "xx");task.Signal(); //觸發令牌流轉所有的操作都通過Facade模式集中到BpmContext中,操作簡單方便。
2、接下來我們先看看流程定義的XML,以下是我捏造的一個流程,以便把各種節點都放進去了。
<?xml version="1.0" encoding="UTF-8"?><process name="樣板房裝修流程"> <start name="裝修申請"> <transition to="裝修方案設計" > <action class="Namespace.MyActionHandler"></action> </transition> </start> <task name="裝修方案設計"> <transition to="裝修方案審核"> <action scraccess="read,required"></variable> </variables> </decision> <fork name="裝修籌備"> <transition to="裝修合同簽定"></transition> <transition to="等待裝修工人到位"></transition> <transition to="裝修材料預算"></transition> </fork> <sign name="裝修合同簽定" necessary="false" async="true"> <transition to="裝修施工"></transition> </sign> <wait name="等待裝修工人到位"> <transition to="裝修施工"></transition> </wait> <task name="裝修材料預算"> <transition to="材料采購子流程"></transition> </task> <subflow name="材料采購子流程"> <transition to="裝修施工"></transition> </subflow> <join name="裝修施工"> <transition to="施工驗收/付款"></transition> </join> <auto name="施工驗收/付款"> <transition to="裝修完成"></transition> </auto> <end name="裝修完成"> </end> <events> <action event="process-start" class="TestStartHandler"></action> <action event="process-end" class="TestEndHandler"></action> </events> <variables> <variable type="string" name="start_id" access="readonly,required"></variable> <variable type="string" name="start_person"></variable> </variables></process>
定義的根節點為流程(process),流程下為各個任務節點(node),任務節點分為: start 開始節點 auto 自動節點 task 人工節點 decisioin 決策節點 fork 發散節點 join 聚合節點 sublfow 子流程節點 sign 會簽節點 wait 等待節點end 結束節點
任務節點下可以包括路由(transition)動作(action)及人員分配(assignment)變量定義(variable) 其中action包括幾種類型:1、class 2、script 3、sql 4、webservice 5、expression 在script或expression中可以直接訪問process.xxx屬性或task.xxx屬性或variable.xxx簡化了動態c#語句的使用。 當然XML定義中還有很多其它的屬性定義我這里也沒有都列出來,以后用到了再仔細說。
3、關于數據庫設計,這里僅僅是流程流轉核心所需要的表,表之間都沒有拉關系
a、我把它劃分為主要的幾大模塊: 引擎配置、流程定義、實例流轉、日志處理、計劃任務 引擎配置:配置引擎實例的數據庫連接、日志配置、參數設定等。 流程定義:利用xml來描述流程,主要定義任務節點,路由、動作事件、變量、人員分配等 實例流轉:根據定義運行流程實例 日志處理:輸出日志 任務計劃:會啟動一個服務,用于處理比如延時啟動,任務過期等
b、流轉中的關鍵性類設計包括: 1、流程對象(Process) 2、工作任務(Task) 3、路由(Trasition) 4、令牌(Token) 5、事件總線與動作處理 (EventBus、ActionHandler) 6、人員分配及委托機制(Assignment、Depute) 7、流程回退處理(RollbackService) 8、消息服務(NotifyService)
c、通常引擎控制流程調度流轉核心的調度算法主要有FSM以及PetriNet兩種,基于調度算法來完成流程的流轉: 1、FSM(有限狀態機) FSM 的定義為包含一組狀態集(states)、一個起始狀態(start state)、一組輸入符號集(alphabet)、一個映射輸入符號和當前狀態到下一狀態的轉換函數(transition function)的計算模型。當輸入符號串,模型隨即進入起始狀態。它要改變到新的狀態,依賴于轉換函數。在有限狀態機中,會有有許多變量,例如,狀態機有很多與動作(actions)轉換(Mealy機)或狀態(摩爾機)關聯的動作,多重起始狀態,基于沒有輸入符號的轉換,或者指定符號和狀態(非定有限狀態機)的多個轉換,指派給接收狀態(識別者)的一個或多個狀態,等等。遵循FSM流程引擎通過狀態的切換來完成流程的流轉。 2、PetriNet 信息流的一個抽象的、形式的模型。指出一系統的靜態和動態性質。PetriNet通常表示成圖。遵循PetriNet流程引擎通過令牌來決定流程的流轉。 我采用的是第二種PetriNet算法。用Token來表示當前實例運行的位置,也利用token在流程各個點之間的轉移來表示流程的推進,如下圖所示: 令牌流轉邏輯,我把以下類方法都做一個簡化省略了路由選擇及節點處理細節,好讓大家明白令牌的流轉:
//令牌Token類中Signalpublic void Signal() { fromTask.Leave(executeContext);}//任務Task類中的Leavepublic void Leave(ExecutionContext executionContext){ transition.Take(executionContext);}//路由Transition類中的Takepublic void Take(ExecutionContext executionContext){ toTask.Enter(executionContext);}//任務Task類中的Enterpublic void Enter(ExecutionContext executionContext){ Run(executionContext);}
至此令牌成功的從一個節點轉移到下一個節點了,令牌的流轉是工作流的關鍵,當然不同的節點處理是有所不同的,其中最復雜的當數發散節點及聚合節點了。這里就介紹到這里,不再給大家詳細介紹了。
d、目前我引擎中實現的主要包括以下功能: 1、解釋過程定義 2、控制過程實例—創建、激活、掛起、終止等 3、控制流程調度流轉 4、自定義動作及事件發布 5、流程變量及工作變量處理 6、任務計劃,比如延時啟動,任務過期等 7、委托服務,委托代辦 8、回退服務,回退到任意節點或召回 9、消息服務,比如認領通知、待辦提醒、催辦消息… 10、流程任務監控服務 11、日志處理及歷史記錄 12、任務分配與認領 13、參與者組織模型接口
目前我的這款工作流引擎還在繼續完善當中,我總結下它的優缺點: 優點: 1、它是一款超輕量極或者說是微型的工作流引擎,而且綠色無污染,它只有一個dll,大小僅1M左右。 2、它目前支持SQL Server、MySQL、Oracle、SQLite、PostgreSql等多種數據庫 3、體型上來說它雖然是微型,但功能上并不算微型,它的設計結合了現代的OA及傳統工作流、基本上可以實現我們大多數的功能需要。 4、它其實是面向開發者設計的,從上面初始印象中的實例代碼中大家可以看到,它的接口是很集中、精簡、友好的,讓開發者容易理解而且使用起來更方便簡單。所以它更適合嵌入到項目中開發。 缺點: 1、它現在沒有流程設計器、管理系統、表單設計器等,充其量只能算是一個類庫,并不是直接拿來就可以使用。 2、目前剛剛完成第一個內部版本,而且目前只在我們內部項目中使用,所以它不夠成熟,雖然我們會持續的改進和完善。 3、缺乏成功應用的案例。 對于我們自己來說,這些缺點都是我們需要繼續努力的地方,可能還需要大量的時間來完成。目前來說我們還不打算開源,等它慢慢穩定成熟后我們會考慮是不是開源出來。如果大家有好的建議或有哪方面的疑惑我很樂意給大家解答,或者你也在設計開發自己的工作流,我們可以相互交流下。
新聞熱點
疑難解答