Java工作流引擎:jBPM、Activiti以及SWF

這只是一篇非常粗淺的記錄我對(duì)工作流引擎認(rèn)識(shí)的文章。

知道工作流引擎是很久之前了,但是一直都沒(méi)有機(jī)會(huì)嘗試,一是沒(méi)有業(yè)務(wù)上的需要,二是感覺(jué)工作流入門(mén)不容易。最近,項(xiàng)目中用到了一點(diǎn)工作流的東西,雖然我沒(méi)有具體參與,但是了解一下還是好的。于是抽周末兩天時(shí)間讀了一些文章和jBPM以及Activiti的User Reference,本文做一下記錄。SWF指的是Amazon Simple Workflow。

工作流引擎是什么?

“工作流引擎”這個(gè)名字聽(tīng)起來(lái)很?chē)樔耍ā耙妗边@兩個(gè)字眼總是能?chē)樔说模?,我之前就是被嚇著了的程序員中的一個(gè)。百度詞條“工作流引擎”也很難懂。

我們經(jīng)常做一些程序,比如用戶A填一張表,提交后,會(huì)給另一個(gè)用戶B(通常是另一類較色)審核,他們覺(jué)得沒(méi)有問(wèn)題就確定,最后給原來(lái)A用戶發(fā)送一封郵件。在實(shí)現(xiàn)這一類系統(tǒng)時(shí)我們會(huì)設(shè)計(jì)一張任務(wù)表,這個(gè)表中有一列成為Status(狀態(tài)):用戶提交后狀態(tài)是0,審核通過(guò)后狀態(tài)是1,審核沒(méi)通過(guò)狀態(tài)是2。但是這樣設(shè)計(jì)會(huì)有一些擴(kuò)展性的問(wèn)題,比如:

我需要知道某表單的歷史信息:什么時(shí)候由誰(shuí)提交、什么時(shí)候被審核通過(guò)、被誰(shuí)審核通過(guò)等

我需要擴(kuò)展或者改動(dòng)流程:A用戶提交表單后,B用戶希望能收到郵件提醒等

我需要定時(shí)執(zhí)行一些任務(wù):為A用戶提交表單設(shè)置截止時(shí)間,提前截止時(shí)間一天發(fā)送郵件通知

注:這些需求用土鱉的方式是都可以實(shí)現(xiàn),我以前在學(xué)校工作的時(shí)候,買(mǎi)設(shè)備走學(xué)校的采購(gòu)流程系統(tǒng),我就親眼看到一個(gè)工作人員打開(kāi)SQL Server去數(shù)據(jù)庫(kù)中查詢這個(gè)訂單是什么時(shí)候下的。

當(dāng)然,這樣的系統(tǒng)做得多了,就會(huì)對(duì)這些進(jìn)行歸納抽象,比如:

將任務(wù)狀態(tài)表和歷史記錄表抽象出來(lái)成為?TaskService?和?HistoryService?模塊

將定時(shí)任務(wù)以及抽象成?BusinessCalendar?模塊

將用戶管理的部分抽取出來(lái)成為?Identity?模塊

將發(fā)送郵件抽象成?EmailTask?模塊,使用的時(shí)候只需要配置一下收件人和內(nèi)容即可

將需要調(diào)用Java類處理業(yè)務(wù)邏輯功能抽象成?Action,使用時(shí)配置一下具體調(diào)用哪一個(gè)Java類

最后做一個(gè)流程管理的通用界面,能實(shí)時(shí)監(jiān)控流程的執(zhí)行情況

這些也都是jPBM以及Activiti等工作流引擎的核心模塊。

工作流引擎的基本概念

上一節(jié)所述A和B參與的工作流的例子,很好的描述了一個(gè)A和B的工作流程,我們用一種語(yǔ)言來(lái)將這種模式描述出來(lái),jBPM5之前版本用的是jPDL,現(xiàn)在大家都用BMPN,兩者大同小異,都是用XML來(lái)描述流程,也都有可視化設(shè)計(jì)器支持,不過(guò)BMPN是行業(yè)標(biāo)準(zhǔn)。

編寫(xiě)好流程定義(Process Defintion)文件以及相關(guān)的Java類后,就可以部署到引擎中,每一次執(zhí)行稱為一個(gè)流程實(shí)例(Process Instance)。

工作流有版本的概念,jBPM和Activiti上傳一個(gè)新的版本后,版本號(hào)會(huì)增加1,舊版本還沒(méi)執(zhí)行完的流程實(shí)例還會(huì)繼續(xù)執(zhí)行。SWF的版本是個(gè)字符串,隨意指定好了,這樣也很好,字符串名稱更明確。

前面提到工作流抽象出來(lái)的各個(gè)模塊,他們之間也是需要相互交互的,比如?EmailTask?就需要調(diào)用?Identity?模塊來(lái)查找用戶的Email信息、用戶的姓名等。因此需要一個(gè)流程上下文(Process Context)來(lái)協(xié)調(diào)。

最后,流程的各個(gè)Task(或者稱為Activity)之間可能要共享一點(diǎn)信息,jBPM和Actviti都有流程上下文實(shí)例(Process Context Instance)的概念,很像一個(gè)Hash,存放key-value信息,當(dāng)然比Hash更強(qiáng)一點(diǎn)的是,流程上下文實(shí)例支持作用域的概念。

工作流引擎的組成部分

流程定義

所謂流程定義即使用XML編寫(xiě)的用于描述流程的文件,你需要掌握一些BMPN的知識(shí)。很多工作流引擎都帶有可視化流程設(shè)計(jì)器,但是需要理解的是,背后其實(shí)還是XML,下面是一個(gè)定義了4個(gè)結(jié)點(diǎn)的示例。

? ? ? ? ? ? ? ? ? ? execution.setVariable("message", "Hello")? ? ? ? ? ? ? ? ? ?

定以好流程后,就可以發(fā)布到工作流引擎,工作流引擎負(fù)責(zé)解析這個(gè)XML,并且存到數(shù)據(jù)庫(kù)中。我們通過(guò)API來(lái)啟動(dòng)一個(gè)流程。

API

對(duì)于苦逼的程序員來(lái)講,API就是一切,不過(guò)經(jīng)過(guò)抽象后的API也不復(fù)雜,基本上還是前面前面一節(jié)所述的概念的抽象。下面是Activiti工作流引擎部署流程定義文件,并啟動(dòng)一個(gè)流程的示例代碼:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();RepositoryService repositoryService = processEngine.getRepositoryService();repositoryService.createDeployment().addClasspathResource("Demo1.bpmn").deploy();RuntimeService runtimeService = processEngine.getRuntimeService();ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");

流程啟動(dòng)后,可以通過(guò)API來(lái)對(duì)流程進(jìn)行控制,如觸發(fā)一個(gè)消息等待任務(wù)(receiveTask),甚至是將任務(wù)分配給某個(gè)用戶,獲取某個(gè)用戶的所有任務(wù)等。

List tasks = taskService.createTaskQuery()? ? .taskAssignee("admin")? ? .orderByDueDate().asc()? ? .list();

這段代碼是查詢admin用戶的所有任務(wù),按照截止時(shí)間升序排序,也就是最緊急的放在最前面。

嵌入式部署與獨(dú)立

嵌入式部署即將流程引擎嵌入部署于Web應(yīng)用中,這是最容易也是最簡(jiǎn)單的方式,通過(guò)上面的API就可以實(shí)現(xiàn)。

獨(dú)立部署即流程引擎被獨(dú)立運(yùn)行,Web應(yīng)用通過(guò)Rest API或者其他方式調(diào)用流程引擎的接口。Activiti引擎實(shí)現(xiàn)了一套R(shí)est API,SWF也實(shí)現(xiàn)了完整的API結(jié)構(gòu),包括各個(gè)語(yǔ)言的版本。

獨(dú)立部署的好處就是,引擎獨(dú)立運(yùn)行,和外部系統(tǒng)很好的解耦了,外部系統(tǒng)的故障不會(huì)導(dǎo)致工作流引擎的崩潰。

SWF

SWF與其說(shuō)是工作流引擎,不如說(shuō)是分布式計(jì)算調(diào)度框架,SWF中只包括Task和History兩部分,甚至是每個(gè)Task之間如果要傳遞一些數(shù)據(jù)的話,都只能通過(guò)第三方存儲(chǔ)(比如Message Queue或者Redis),不過(guò)這也給了編程更大的靈活性,問(wèn)題是這種靈活性是不是非常需要。

一個(gè)SWF由Worker和Decider組成,Worker執(zhí)行實(shí)際的任務(wù),而Decider進(jìn)行流程控制,兩者嚴(yán)格上來(lái)講沒(méi)有區(qū)別,只是所執(zhí)行的任務(wù)不同罷了。每個(gè)Worker和Decider會(huì)定期的去SWF的一個(gè)Task List取下一個(gè)任務(wù)??梢钥闯鰜?lái)這更像是一個(gè)“多線程”的結(jié)構(gòu),而SWF官方網(wǎng)站的Use Case是NASA的火星探索計(jì)劃中需要處理圖片的系統(tǒng),這其實(shí)也是一個(gè)更多側(cè)重于計(jì)算的系統(tǒng),流程反而非常簡(jiǎn)單。

另外,SWF(Simple Workflow)的一個(gè)Workflow不能太復(fù)雜,因?yàn)樗械牧鞒炭刂贫技杏贒ecider,如果太復(fù)雜的話Decider將無(wú)比龐大,給維護(hù)和擴(kuò)展帶來(lái)一定的困擾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容