專利名稱::高性能業(yè)務(wù)能力封裝流程引擎及其流程控制方法高性能業(yè)務(wù)能力封裝流程引擎及其流程控制方法
技術(shù)領(lǐng)域:
:本發(fā)明涉及計算機流程處理領(lǐng)域,特別是指ー種高性能業(yè)務(wù)能力封裝流程引擎及其流程控制方法。背景技木目前流程引擎的產(chǎn)品有很多,如jBPM、OSWorkflow、ApacheODE、WebSphereProcessServer、OracleAqulogic、MicrosoftBizTalk等,在國內(nèi),主要是使用上述幾個引擎做擴展和應(yīng)用,而且絕大部分是使用Java或C++實現(xiàn),主要是因為電子商務(wù)在流程引擎方面的應(yīng)用較多,對于性能優(yōu)化的側(cè)重點一般不在流程引擎上,但是,C/C++語言在性能上的先天優(yōu)勢,某些系統(tǒng)對實時性要求較高的情況下,本身也使用C/C++語言進行開發(fā),需要和流程引擎進行較緊密的結(jié)合,并保證流程引擎不會給程序的運行帶來明顯的性能上的影響。流程引擎的主要功能是執(zhí)行業(yè)務(wù)流程,是BPM的架構(gòu)核心,其設(shè)計好壞、效率高低直接影響到整個BPM的性能高低。當(dāng)然這種對效率要求較高的流程引擎一般應(yīng)用在針對自動流程的環(huán)境下,這類應(yīng)用往往關(guān)注的是“快速”而不是龐大的功能集。
發(fā)明內(nèi)容本發(fā)明所要解決的技術(shù)問題之ー在于提供ー種高性能業(yè)務(wù)能力封裝流程引擎,從各個方面提高了流程引擎的性能,經(jīng)過測試達到了業(yè)務(wù)系統(tǒng)對性能的要求。本發(fā)明所要解決的技術(shù)問題之ニ在于提供ー種高性能業(yè)務(wù)能力封裝流程控制方法,從各個方面提高了流程引擎的性能,經(jīng)過測試達到了業(yè)務(wù)系統(tǒng)對性能的要求。本發(fā)明采用以下技術(shù)方案解決上述技術(shù)問題之一高性能業(yè)務(wù)能力封裝流程引擎,包括流程定義單元,用于生成規(guī)定流程各節(jié)點功能以及流程執(zhí)行規(guī)則的配置文件,所述流程由節(jié)點和節(jié)點間的關(guān)系組成;流程解析與加載單元,用于讀取流程定義單元的配置文件將其轉(zhuǎn)換為流程的對象且保存于內(nèi)存中;流程與節(jié)點的交互単元,用于執(zhí)行以規(guī)則為主線串接各個流程節(jié)點,對各個節(jié)點進行調(diào)用并與之交互,根據(jù)節(jié)點的返回結(jié)果通過判斷節(jié)點影響流程實例的執(zhí)行路線;流程執(zhí)行單元,用于根據(jù)流程定義創(chuàng)建對應(yīng)的流程實例時,在內(nèi)存中申請空間存放和維護流程變量、流程數(shù)據(jù)以及流程實例和各節(jié)點的狀態(tài)數(shù)據(jù);流程監(jiān)控單元,用于通過IPC訪問內(nèi)存中實例的節(jié)點狀態(tài)、執(zhí)行時間、流程變量值信息,并將其封裝為一系列查詢接ロ,通過網(wǎng)絡(luò)共同遠程監(jiān)控終端進行訪問;流程日志単元,用于通過消息機制觸發(fā)日志處理,采用多線程的并行處理方式將流程實例執(zhí)行的成功與否以及各節(jié)點執(zhí)行情況和時間保存到數(shù)據(jù)庫,并將該流程實例從共享內(nèi)存中的空間釋放出來。進ー步,所述節(jié)點包括開始、結(jié)束、函數(shù)、腳本、狀態(tài)、分支、匯聚;所述節(jié)點間的關(guān)系包括前驅(qū)和后續(xù)。本發(fā)明采用以下技術(shù)方案解決上述技術(shù)問題之ニ高性能業(yè)務(wù)能力封裝流程控制方法,包括如下步驟生成規(guī)定流程各節(jié)點功能以及流程執(zhí)行規(guī)則的配置文件,所述流程由節(jié)點和節(jié)點間的關(guān)系組成;讀取流程定義單元的配置文件將其轉(zhuǎn)換為流程的對象且保存于內(nèi)存中;執(zhí)行以規(guī)則為主線串接各個流程節(jié)點,對各個節(jié)點進行調(diào)用并與之交互,根據(jù)節(jié)點的返回結(jié)果通過判斷節(jié)點影響流程實例的執(zhí)行路線;根據(jù)流程定義創(chuàng)建對應(yīng)的流程實例時,在內(nèi)存中申請空間存放和維護流程變量、流程數(shù)據(jù)以及流程實例和各節(jié)點的狀態(tài)數(shù)據(jù);通過IPC訪問內(nèi)存中實例的節(jié)點狀態(tài)、執(zhí)行時間、流程變量值信息,并將其封裝為一系列查詢接ロ,通過網(wǎng)絡(luò)共同遠程監(jiān)控終端進行訪問;通過消息機制觸發(fā)日志處理,采用多線程的并行處理方式將流程實例執(zhí)行的成功與否以及各節(jié)點執(zhí)行情況和時間保存到數(shù)據(jù)庫,并將該流程實例從共享內(nèi)存中的空間釋放出來。進ー步地,所述節(jié)點包括開始、結(jié)束、函數(shù)、腳本、狀態(tài)、分支、匯聚;所述節(jié)點間的關(guān)系包括如驅(qū)和后續(xù)。本發(fā)明的優(yōu)點在干本發(fā)明使用C++作為引擎核心的編寫語言,使用Lua作為腳本節(jié)點以及判斷節(jié)點的應(yīng)用,從程序執(zhí)行方面對性能進行了提高。流程引擎在執(zhí)行過程中對流程定義的讀取以及日志的保存如果都使用數(shù)據(jù)庫或者文件,會給性能帶來較大瓶頸,所以高效流程引擎使用共享內(nèi)存作為流程定義、流程實例、流程日志等的數(shù)據(jù)緩存,并使用其他模塊來對流程定義進行加載和日志的落地。高效流程引擎從各個方面提高了流程引擎的性能,經(jīng)過測試達到了業(yè)務(wù)系統(tǒng)對性能的要求。下面參照附圖結(jié)合實施例對本發(fā)明作進ー步的描述。圖I是本發(fā)明流程引擎總體架構(gòu)圖。圖2是本發(fā)明節(jié)點定義示意圖。圖3是本發(fā)明各節(jié)點的類圖關(guān)系示意圖。圖4是本發(fā)明流程定義緩存圖。圖5是本發(fā)明各種腳本語言執(zhí)行效率的對比數(shù)據(jù)圖。圖6是本發(fā)明C/C++和Lua的交互關(guān)系示意圖。圖7是本發(fā)明Lua對棧的定義示意圖。圖8是本發(fā)明C/C++調(diào)用Lua過程棧的變化示意圖。圖9是本發(fā)明Lua調(diào)用C/C++接ロ過程棧的變化示意圖。圖10是本發(fā)明判斷節(jié)點示意圖。圖11是本發(fā)明流程監(jiān)控示意圖。圖12是本發(fā)明流程日志處理示意圖。具體實施方式提高流程引擎的性能,就必須提高流程引擎執(zhí)行內(nèi)核的效率,讓流程的執(zhí)行環(huán)境在內(nèi)存中進行,所以本發(fā)明在架構(gòu)中引入了緩存部分,設(shè)計專門的流程加載模塊可以將配置數(shù)據(jù)向緩存中加載,同時還設(shè)計專門的數(shù)據(jù)同步模塊能將緩存中執(zhí)行結(jié)束的流程實例同步到持久層,而流程引擎的使用者通過接ロ調(diào)用流程執(zhí)行的時候只會在緩存中進行,故而能提高流程引擎的性能。如圖I所示,是本發(fā)明流程引擎總體架構(gòu)圖。業(yè)務(wù)流程必然和功能模塊打交道,本發(fā)明將一些功能編寫成動態(tài)庫,能在流程中動態(tài)加載并被流程直接調(diào)用,其執(zhí)行的效率和在同一個程序中一祥。另外為支持靈活性和維護的方便性,需要引入ー些即時生效的腳本作為節(jié)點的執(zhí)行內(nèi)容。從執(zhí)行效率以及接ロ效率來評估,使用C/C++語言作為流程引擎核心的編寫語言,而采用和C/C++語言交互性好且執(zhí)行效率很高的腳本語言Lua,是比較合適的方案。下面詳細(xì)介紹本發(fā)明的各単元及步驟I、流程定義流程引擎的設(shè)計是面向圖的設(shè)計,流程都是由兩個最基本的元素組成“節(jié)點”及“有向連接”。對于“有向連接”幾乎沒有任何歧義,所有的流程建模描述中“有向連接”都是存在“From”和“To”這兩個特性。但是對于“節(jié)點”,則因為所處的視角、功能不同,則存在很多不同的理解了,比如WfMC的過程定義元模型、jBPM、EPC中對節(jié)點含義和種類的定義都不太相同。本發(fā)明中的節(jié)點類型包含開始、結(jié)束、函數(shù)、腳本、狀態(tài)、分支(并行、判斷)、匯聚等。如圖2。各種節(jié)點類型的簡要定義如下I)開始節(jié)點一個流程實例啟動后執(zhí)行的第一個節(jié)點,該節(jié)點只有ー個后續(xù)節(jié)點,沒有前驅(qū)節(jié)點,一個流程只能有ー個開始節(jié)點。定義格式如下〈startindex="0">〈transitionto_index="xxx'V></start〉2)結(jié)束節(jié)點流程實例執(zhí)行到該節(jié)點后即結(jié)束,該節(jié)點只有ー個前驅(qū)節(jié)點,沒有后續(xù)節(jié)點,一個流程可以有多個結(jié)束節(jié)點。定義格式如下〈endindex="xxxV>3)函數(shù)節(jié)點為包含業(yè)務(wù)能力的節(jié)點,執(zhí)行動態(tài)庫中的函數(shù)以完成某個業(yè)務(wù)功能,返回后執(zhí)行后ー節(jié)點,該節(jié)點只能有ー個前驅(qū)節(jié)點和ー個后續(xù)節(jié)點。定義格式如下くtasktype="0"index="xxx"func_id="xxx"hangUp="tme/false"><paraTi1;ype="s1:nng./int/double/long/vat·"value=nxxx"/><paramtype="siring/int/doable/long/var"value=,,xxx"/><transitiontoindex="xxx"/></task>4)腳本節(jié)點為包含業(yè)務(wù)能力的節(jié)點,執(zhí)行Lua腳本函數(shù)以完成某個功能,返回后執(zhí)行后ー節(jié)點,該節(jié)點只能有一個前驅(qū)節(jié)點和ー個后續(xù)節(jié)點。定義格式如下<tasktype="I"index="xxx"func_name="xxx"hangUp="true/false">〈transitionto_index="xxx'V>〈/task〉5)狀態(tài)節(jié)點停留在該狀態(tài),等待觸發(fā)信號執(zhí)行后ー節(jié)點,該節(jié)點只能有一個前驅(qū)節(jié)點和ー個后續(xù)節(jié)點。定義格式如下〈stateindex="xxx">〈transitionto_index="xxx'V>〈/state〉6)并行節(jié)點觸發(fā)并行執(zhí)行后續(xù)的多個節(jié)點,該節(jié)點只能有ー個前驅(qū)節(jié)點,但可有多個后續(xù)節(jié)點。定義格式如下<forkindex="XXX"option="0">くtransitiontoindex="xxx"/>transitiontoindex="xxx'!/></fork>7)判斷節(jié)點通過配置在該節(jié)點中的Lua腳本,根據(jù)返回值判斷執(zhí)行后續(xù)的哪個或哪幾個節(jié)點,該節(jié)點只能有ー個前驅(qū)節(jié)點,但可有多個后續(xù)節(jié)點。定義格式如下<rorkindex="xxx"funcname="xxx"option=”I〈transitiontomdex=”xxx”/><transitiontoinciex="xxx"/></fork>8)匯聚節(jié)點等待前驅(qū)節(jié)點全部執(zhí)行完成,觸發(fā)執(zhí)行后續(xù)節(jié)點,該節(jié)點只能有ー個后續(xù)節(jié)點,但可以有多個前驅(qū)節(jié)點。定義格式如下くjoinindex="xxx"><previndex="xxx"/><previndex="xxx"/><transitiontomde\="xxx"/><,(join>可以看出節(jié)點具有共性也有個性,從流程定義的角度,我們將節(jié)點抽象為父類,各種類型的節(jié)點繼承節(jié)點父類,并增加自己的屬性、函數(shù),以及實現(xiàn)節(jié)點執(zhí)行函數(shù)。各節(jié)點的類圖關(guān)系如圖3。將節(jié)點類設(shè)計為ー個抽象類,它包含了純虛函數(shù)virtualexecuteO=0,在執(zhí)行流程時以父類對象指針指向最終節(jié)點類的對象,并調(diào)用父類對象指針的execute函數(shù),則實際會調(diào)用最終子類中的所實現(xiàn)的execute成員函數(shù)。在流程引擎中我們?nèi)コ擞邢蚓€連接對象,即jBPM中的Transition,使用姆個節(jié)點的前驅(qū)或后續(xù)節(jié)點號的方式來貫穿整個流程。任何流程的開始節(jié)點號都定義為O。2、流程解析與加載前臺配置的流程的定義是存儲在數(shù)據(jù)庫中的,一般的流程引擎的做法是每次連續(xù)的執(zhí)行都要到數(shù)據(jù)庫中去讀取流程配置,這樣勢必造成I/o的増加,降低流程引擎的性能。由于流程定義的讀取頻率要遠遠高于寫頻率,所以,要保證流程的高速運轉(zhuǎn),必須將流程定義加載到內(nèi)存中,并且解決好讀寫的沖突問題。流程定義緩存主要分為共享內(nèi)存和私有內(nèi)存兩部分,共享內(nèi)存中是流程定義索引區(qū)和流程定義區(qū),這部分可以由所有的調(diào)用者程序共享讀?。凰接袃?nèi)存中是腳本加載區(qū)和動態(tài)庫加載區(qū),在程序啟動的時候需加載和初始化。流程索引是根據(jù)流程定義ID以及流程的版本號查找流程定義存放的地址的區(qū)域,為了加速流程定義的查找速度。如圖4所示。流程定義使用xml格式配置,調(diào)用rapidxml開源程序中的函數(shù)進行解析,并將配置按類的定義以序列化方式保存在共享內(nèi)存的流程定義中。//開始節(jié)點typedefstructSintnextnode;}START—NODE;//函數(shù)節(jié)點typedefstruct}unsignedchartype;//O-自動執(zhí)行I-執(zhí)行完等待觸發(fā)intfunc—id;/7函數(shù)IDvectorくFUNC—PARAM>*param;//函數(shù)參數(shù)列表指針intnext—node;}FUNC—NODE;//腳本節(jié)點typedefstruct{unsignedchartype;//0-自動執(zhí)行I-執(zhí)行完等待觸發(fā)charfunc—name[50:j;/./腳本函數(shù)名intnextnode;jSCRIPT—NODE;//狀態(tài)節(jié)點typedefstruct{unsignedchartype;//0-不阻塞I-阻塞等待觸發(fā)iiUnextnode;JSTATE—NODE;//分支節(jié)點tvpederstruct{unsignedchartype;"0-并行、I-判斷charfunc_name[50];"腳本函數(shù)名intnext—node[MAXFORK];}KORKNODH;//匯聚節(jié)點typedefstruct{intprev_node[MAX_JOIN];//匯聚節(jié)點號列表intnextnode;}JOIN—NODE;//各種類型節(jié)點聯(lián)合體typedefunion{START—NODEstart—node;FliNC—NODEfuncnode;SCRiPTNOI)Rsciiptnode;SlAiHNODt;state—node;FORK—NODEfork—node;JOINNODEjoin—node;}NODE;//節(jié)點類型和節(jié)點typedefstruct{unsignedcharnodetype;/./_レ'點矢型NODEnode;//節(jié)點)BPM—NODE;//流程定義typedefstruct{Intflowdefid;/7沒程定義TDshortflowdefver;//流程定義版本boo!valid;//是否有效VARDEFvai·—def[MAX—FしOW—VAR];"流程變量定義BPMNODEbprn—node[MAX—NODE];//節(jié)點定義vectorくFUNC—PARAM〉func_param[MAX_NODE];.//函數(shù)的參數(shù)}FLOW_DEF;在共享內(nèi)存中就是以FL0W_DEF類型的結(jié)構(gòu)數(shù)組的方式存儲多個流程定義。由于流程的執(zhí)行是ー個持續(xù)的過程,在流程實例未結(jié)束之前,改流程實例使用的流程配置都應(yīng)該保持在內(nèi)存中且不能被改動。對于新增的流程,在流程定義區(qū)新開辟空間并上載新流程定義,上載完成后鎖定流程定義索引區(qū),更新Hash(流程定義ID,流程版本)和流程定義存放地址的對應(yīng)關(guān)系,然后解鎖;對于要刪除的流程,一般是將該流程打上刪除標(biāo)志而不是立即刪除,由流程上載模塊負(fù)責(zé)查詢沒有使用該流程定義的流程實例后將其刪除并回收空間;對于修改的流程,采用升級的方式處理,也就是先將新的流程加載到新開辟的流程區(qū),并更新流程定義索引區(qū),新的流程實例會按新版本執(zhí)行,當(dāng)使用舊版本的流程實例全部結(jié)束后,流程上載模塊會將舊版本的流程定義刪除并回收空間。通過這樣的增、刪、改的機制可以解決流程定義讀寫的沖突。3、流程與節(jié)點的交互流程引擎是由一個執(zhí)行規(guī)則串接各個流程節(jié)點來完成的,這個規(guī)則就是各個節(jié)點間的關(guān)系,也就是流程引擎的主線,而掛接在這個主線上的函數(shù)節(jié)點和腳本節(jié)點實現(xiàn)的是具體的業(yè)務(wù)能力(功能),主線需要對各個節(jié)點進行調(diào)用和并與之交互,并可以根據(jù)節(jié)點的返回結(jié)果通過判斷節(jié)點影響流程實例的執(zhí)行路線。除了功能之外,流程函數(shù)能増加流程引擎的快速性,而流程腳本能增強流程引擎的靈活性同時也不失快速性。3.I流程函數(shù)對于流程引擎來說,調(diào)用節(jié)點中定義的業(yè)務(wù)功能是重要的,很多流程引擎在SOA思想的影響下,在考慮通用性方面,會考慮使用通用的接ロ調(diào)用功能,如使用WebService和外部的服務(wù)進行通信,還有的是采用調(diào)用java類的方式,如jBPM。而高效流程引擎在則是采用調(diào)用C語言編寫的動態(tài)庫的方式,這樣在加載之后執(zhí)行動態(tài)庫中函數(shù)的速度和執(zhí)行程序本身的函數(shù)是ー樣的,能大大增強執(zhí)行效率。C語言中可以將功能函數(shù)編譯成動態(tài)庫(.so),然后使用dlopen函數(shù)在流程引擎加載流程定義時加載到私有內(nèi)存,在調(diào)用動態(tài)庫函數(shù)的時候使用dlsym函數(shù)獲取函數(shù)指針,然后就可以調(diào)用函數(shù)了。如下是打開動態(tài)庫和獲取函數(shù)指針的代碼typedefbool(*FUNC_TYPE)(void*in_paraml,void*in_param2,…);void*func_handle=dlopen("·/evtproc/evtproc.so",RTLD_LAZY);FUNC_TYPEfunc=(FUNC_TYPE)dlsym(func_handle,"func_name");在動態(tài)庫加載區(qū)中建立函數(shù)ID和函數(shù)指針的HashMap對應(yīng)關(guān)系,在流程定乂中只保存函數(shù)ID,在調(diào)用之前使用函數(shù)ID在HashMap中查找對應(yīng)的函數(shù)指針。動態(tài)庫可以在程序運行過程中隨時加載,這給流程定義的熱布署帶來很大的方便。3.2流程腳本腳本具有靈活性強、能立即生效等特點,在流程引擎的節(jié)點中使用腳本可以帶來靈活性和擴展性,對于高效引擎來說,即使是腳本也不能失去高效性。3.2.ILua腳本以及與C/C++的交互Lua腳本語言是用標(biāo)準(zhǔn)C編寫而成的嵌入式腳本語言,和C/C++有良好的交互性,能為應(yīng)用程序提供靈活的擴展和定制功能,而且?guī)缀踉谒胁僮飨到y(tǒng)和平臺上都可以編譯和運行。Lua是腳本語言中執(zhí)行效率最高的,且很輕量級,內(nèi)存占用很少。經(jīng)過對相同的浮點數(shù)運算程序測試,以C語言(編譯器gcc4.0.I)為基準(zhǔn),進行速度測試,可得出如圖5的各種腳本語言執(zhí)行效率的對比數(shù)據(jù)。C/C++程序中對Lua庫的初始化,需要使用lua_open函數(shù)初始化并獲得Lua環(huán)境句柄指針,然后使用luaL_openlibs加載Lua的庫,并包含所有Lua函數(shù)的Lua腳本進行加載。多次加載Lua腳本,如果加載了相同名稱的函數(shù),后面的會將前面覆蓋。#include<lua.hpD>luaStatevgpLuaState;stringluascript;gpLuaState=luaopenQ;//打開Lua環(huán)境句柄IuaLopeniibs(spLuaState);//カロ載Lua庫............//對腳本lua—script進行賦值luaLdostring(gpLuaState,lua_script.c_str());//加載lua函數(shù)腳本Lua和C語目的交互,一般是Lua嵌入到C/C++程序中,簡單的功能可以直接由Lua函數(shù)提供,如果Lua完成不了的,也可以編寫可由Lua調(diào)用的C/C++接ロ函數(shù),讓Lua起到橋梁作用,快速重組這些接ロ函數(shù)。C/C++和Lua的交互如圖6所示,主要是通過棧來進行的,Lua規(guī)定棧的位置如果自下而上最下為1,依次向上加I;如果自上而下則最上為-1,依次向下減I。Lua對棧的定義如圖7所示。下面來分析一下,C/C++和Lua交互的具體細(xì)節(jié)1)C/C++調(diào)用LuaC/C++調(diào)用Lua首先使用lua_getglobal獲取Lua函數(shù)同時自動將函數(shù)壓入棧,然后使用lua_push系列函數(shù)將參數(shù)依次壓入棧,然后使用lua_pcall函數(shù)調(diào)用Lua函數(shù),調(diào)用完成時函數(shù)和參數(shù)都已由Lua自動彈出,棧中只保留Lua的返回值,C/C++從棧中將Lua的返回值取出,最后清空棧。在C/C++將參數(shù)壓入棧時,如果參數(shù)都是基礎(chǔ)類型(如int、char*等)只需要用lua_pushnumber和lua_pushstring函數(shù)即可,但是如果壓入的參數(shù)是結(jié)構(gòu)體,則需要和Lua的table進行對應(yīng)。Lua的返回值可以是數(shù)組,可以將返回值里數(shù)組成員逐個取出。下面用圖8所示C/C++調(diào)用Lua過程棧的變化示意圖和代碼的方式來描述ー下C/C++所調(diào)用的Lua函數(shù)參數(shù)帶一個結(jié)構(gòu)和ー個簡單類型,返回值為ー個簡單類型和ー個數(shù)組的混合方式的交互。調(diào)用Lua的C++代碼boolcallLuaichar"'funcname,structENVenv,intnodeid,vector<mt>&resLill){lui_getglobal(gpLuaState,funcname):"獲取Luai^數(shù),并同時氏4將函數(shù)壓入了棧Iuanewtable(gpT.uaState);//創(chuàng)建table,并自動將其壓入了找//壓入結(jié)構(gòu)中的一個成員,table變成了棧自頂向下的第2個元素]ua_piishniimber(gpLiiaState,env.flowinstid);//ヌ十找的Luatable的flowinstid元素,同時棧頂元素被自動彈出luasetfield(gpLuaState,-2,"flowmstid");!ua_pushnunibcr(gpLuaStatc,cnv.tlowdcfid);luasetfield(gpLuaState,-2,"flowdefid");lLia_puslmLimber(gpLiiaSiale,node—id);//將第二個參數(shù)壓入戲//調(diào)用Lua函數(shù),調(diào)用完畢后棧中只有Lua的返回值IuapcalllgpLuaState,2,2,O)!=O);intretnuni=IuaLgetn(gpLuaState,-1);for(inti=l;i<=ret_num;i十-.-.)/./取返回イ直{Iua_rawgeti(gpLuaState,-I,i);result.push_back(IuatoiiuinberiiipLuaState,-!));lua—pop(gpしuaState,I);,}luapop(gpLuaState,I);//將數(shù)組遂回值彈出boolret=luatoboolean(gpLuaState,-I);lua_pop(gpLuaSiate,I);/74手棧清Sireturnret;}Lua'腳本代碼functionchcck(cnv,nodcicl)localflow」nst—id=env.f!ow—inst—idlocalHowdefid=env.flow—defニidreturntrue,(101,102)end2)Lua調(diào)用C/C++接ロLua調(diào)用C/C++接ロ首先將C/C++接ロ注冊為ー個Lua函數(shù),如下lua_register(gpLuaState,getFlowVarlnt,c41ua_getFlowVarIntVal);其中g(shù)etFlowVarlnt是Lua函數(shù)名,c41ua_getFlowVarIntVal是C/C++接ロ函數(shù)名,在注冊■完了之后,在Lua里就可以調(diào)用getFlowVarlnt函數(shù),就等于是調(diào)用了c41ua_getFlowVarIntVal函數(shù)。Lua函數(shù)調(diào)用C/C++接ロ函數(shù)的參數(shù)傳入以及返回值傳出均是使用棧來進行,接ロ函數(shù)本身的定義必須包含且只能包含ー個lua_State指針參數(shù),為Lua環(huán)境句柄指針,函數(shù)返回值必須為int型,代表接ロ函數(shù)寫到棧中的給Lua函數(shù)的返回值的個數(shù)。接ロ函數(shù)形式如下intc41ua_getFlowVarIntVal(lua_State*L);Lua函數(shù)在調(diào)用接ロ函數(shù)注冊函數(shù)吋,會自動將其傳入的Lua參數(shù)寫入棧,假定Lua函數(shù)getFlowVarlnt在被調(diào)用時傳入了兩個參數(shù)參數(shù)I為int型,參數(shù)2為string型,Lua在調(diào)用C/C++接ロc41ua_getFlowVarIntVal時,會將參數(shù)按前后次序壓入棧,然后調(diào)用函數(shù)接ロ,這些棧操作部分都是由Lua自動完成的,無需用戶操作。而接ロ函數(shù)c41ua_getFlowVarIntVal中的需用戶實現(xiàn)的部分則必須對棧進行操作,先獲取調(diào)用自己的Lua函數(shù)傳遞的參數(shù),使用lua_tonumber(gpLuaState,-I)獲取第I個參數(shù),lua_tostring(gpLuaState,-2)獲取第2個參數(shù),并在執(zhí)行完業(yè)務(wù)代碼后將Lua函數(shù)所需的返回值壓入棧,這些返回值將會被Lua函數(shù)自動取得,Lua支持多個返回值,如函數(shù)有2個返回值,用lua_pushnumDer(gpLuaState,100),lua_pushboolean(gpLuaState,true)Bi人找,并且C/C++接ロ函數(shù)本身返回值為2,代表壓入棧的給Lua函數(shù)的返回值的個數(shù)。如圖9所示為Lua調(diào)用C/C++接ロ過程棧的變化示意圖。intc41ua—getFlowVarlntVal(lua—State*L){intflow_id=lua_tonumber(L,-I);//參數(shù)按倒序提取,先取最后I個參數(shù)char*var_name=]ua_tostring(L,-2);//再取.第I個參數(shù)intvalue=getFlowVarIntVal(·)//調(diào)用業(yè)務(wù)處理函數(shù)lua_pushboolean(L,true);//把返回值I壓入棧Iua_pushnumber(L,value);//把返回值2壓入棧return2;//標(biāo)識返回值個數(shù)為2個}Lua函數(shù)的調(diào)用方式則為localret,varval=get:FlowVarInt(10,'varname')3.2.2Lua腳本在判斷節(jié)點的應(yīng)用判斷節(jié)點往往需要經(jīng)過ー些邏輯運算以及比較作出判斷,而邏輯運算有時會比較復(fù)雜,如果單純依靠配置來實現(xiàn)必然會失去靈活性且可能増加配置的復(fù)雜性,如果使用腳本作為判斷節(jié)點的執(zhí)行內(nèi)容,會帶來很多的方便和靈活性,并且由于Lua的語言本身以及它和C/C++交互的高效性,相對其他腳本來說對性能的影響是最小的。對于判斷節(jié)點,配置一個關(guān)聯(lián)的Lua函數(shù),為便于流程引擎的執(zhí)行,所有的判斷節(jié)點Lua函數(shù)為固定的參數(shù)形式以及固定的返回值形式。參數(shù)為兩個一個是流程的相關(guān)信息,table形式,另ー個是節(jié)點號,整數(shù)形式,均由流程引擎?zhèn)魅?;返回值為固定類型?個值,一個為boolean型表示腳本執(zhí)行成功與否,另ー個為int型數(shù)組,其中的元素為后續(xù)可執(zhí)行的節(jié)點號,如果節(jié)點號在該數(shù)組中,則流程引擎認(rèn)為執(zhí)行該節(jié)點的條件滿足,不在數(shù)組中的后續(xù)節(jié)點不執(zhí)行,并且后續(xù)可執(zhí)行節(jié)點可以是多個,即多選。如圖10的流程中的判斷節(jié)點,要判斷節(jié)點I設(shè)置的變量如果大于3則執(zhí)行節(jié)點3和節(jié)點4,如果小于等于3則執(zhí)行節(jié)點5。則判斷節(jié)點的Lua函數(shù)可以寫成functioncheck(env,node—id)localret,varI=getFiowVarlntienv.flowinstid,'varl')ifret==truethenifvarl>3thenreturntrue,}3,4}elsereturntrue,}5}endelsereturnfelse,{}endend4、流程執(zhí)行流程實例是流程定義的一次執(zhí)行,ー個流程定義可以創(chuàng)建多個流程實例。流程引擎使用者根據(jù)流程定義創(chuàng)建對應(yīng)的流程實例時,將在緩存中申請空間存放和維護流程變量、流程數(shù)據(jù)以及流程實例和各節(jié)點的狀態(tài)等數(shù)據(jù)。流程引擎成功創(chuàng)建ー個流程實例后會返回ー個流程實例結(jié)構(gòu)句柄,里面包括了流程實例在緩存中的存放位置指針等一系列信息,流程在執(zhí)行過程中可以根據(jù)指針快速定位流程實例的各種數(shù)據(jù)。每個流程實例的各個節(jié)點的狀態(tài)在共享內(nèi)存中都進行維護,節(jié)點的狀態(tài)分為初始狀態(tài)、等待觸發(fā)、已成功觸發(fā)、已取消、出錯、失敗等。所有節(jié)點在執(zhí)行之前都為初始狀態(tài),有配置為掛起模式的節(jié)點,在第一次成功執(zhí)行后轉(zhuǎn)換為等待觸發(fā)狀態(tài),第二次觸發(fā)后轉(zhuǎn)換為已成功觸發(fā),而未配置為掛起模式的節(jié)點,第一次執(zhí)行完直接轉(zhuǎn)換為成功觸發(fā)狀態(tài)。節(jié)點執(zhí)行出錯的置為出錯狀態(tài),而失敗狀態(tài)則是指外部調(diào)用者以失敗的信號強行將節(jié)點置為失敗。取消狀態(tài)是指在分支節(jié)點判斷完成后,將條件不滿足的后續(xù)節(jié)點置為取消,跳過該節(jié)點而不執(zhí)行。流程的執(zhí)行過程,并從O號節(jié)點開始按照流程定義執(zhí)行,在流程定義索引區(qū)查找流程定義存放的地址,取出當(dāng)前節(jié)點的定義,執(zhí)行該節(jié)點對象的執(zhí)行函數(shù),更新節(jié)點狀態(tài),井根據(jù)執(zhí)行結(jié)果以及節(jié)點的定義確定下一歩的操作。流程實例執(zhí)行到狀態(tài)節(jié)點或函數(shù)、腳本節(jié)點的掛起狀態(tài)時流程掛起,調(diào)用返回,并等待觸發(fā)信號對掛起的節(jié)點進行觸發(fā)繼續(xù)流程實例的執(zhí)行;遇到結(jié)束節(jié)點時,流程實例執(zhí)行結(jié)束,調(diào)用返回,并產(chǎn)生流程結(jié)束消息發(fā)送給流程入庫模塊。一次流程的執(zhí)行,主要就是根據(jù)流程的定義,進行各個節(jié)點的執(zhí)行,每個節(jié)點將執(zhí)行本節(jié)點的executeO方法、修改本節(jié)點狀態(tài)以及調(diào)用后續(xù)的下一(多個)節(jié)點的的執(zhí)行方法executeO進行封裝,稱之為節(jié)點動作,流程就是從觸發(fā)的節(jié)點開始,執(zhí)行節(jié)點動作,以此遞歸執(zhí)行,直到遇到掛起狀態(tài)或流程結(jié)束。下面描述ー下各類型節(jié)點的執(zhí)行方式I)開始節(jié)點無執(zhí)行內(nèi)容,直接調(diào)用下一節(jié)點執(zhí)行動作。2)函數(shù)、腳本節(jié)點判斷狀態(tài)為初始狀態(tài),執(zhí)行本節(jié)點executeO方法,如為掛起模式,修改狀態(tài)為等待觸發(fā),本次執(zhí)行返回;如為非掛起模式,修改狀態(tài)為已觸發(fā),執(zhí)行下ー節(jié)點執(zhí)行動作。判斷狀態(tài)為等待觸發(fā),設(shè)置狀態(tài)為已觸發(fā),執(zhí)行下ー節(jié)點執(zhí)行動作。3)狀態(tài)節(jié)點判斷狀態(tài)為初始狀態(tài),修改狀態(tài)為等待觸發(fā),本次執(zhí)行返回;判斷為的等待觸發(fā)狀態(tài),修改狀態(tài)為已觸發(fā),執(zhí)行下ー節(jié)點執(zhí)行動作。4)并行節(jié)點修改狀態(tài)為已觸發(fā),執(zhí)行后續(xù)的多個節(jié)點動作。5)判斷節(jié)點執(zhí)行判斷節(jié)點的Lua函數(shù),修改狀態(tài)為已觸發(fā),獲取Lua函數(shù)返回值,根據(jù)返回值數(shù)組中的節(jié)點ID,調(diào)用這些節(jié)點ID對應(yīng)的節(jié)點動作。6)匯聚節(jié)點判斷前驅(qū)節(jié)點是否為已觸發(fā)狀態(tài)或取消狀態(tài),如果為“否”本次執(zhí)行返回,如果為“是”修改狀態(tài)為已觸發(fā),執(zhí)行下一節(jié)點執(zhí)行動作。7)結(jié)束節(jié)點結(jié)束流程實例。5、流程監(jiān)控流程的執(zhí)行過程在后臺進行,流程引擎需要提供對流程實例執(zhí)行情況的監(jiān)控。流程實例中的節(jié)點狀態(tài)、執(zhí)行時間、流程變量值等的都在共享內(nèi)存區(qū)中可以通過IPC進行訪問,流程引擎為監(jiān)控提供了一系列查詢接口供同主機的外部進程訪問,并且可以在此基礎(chǔ)上封裝成監(jiān)控服務(wù),供遠程主機訪問和顯示。由于在共享內(nèi)存中進行查詢開銷較少,所以可以提供較為實時的監(jiān)控。如圖11所示,為實現(xiàn)可視化效果較好的流程監(jiān)控,用戶選擇某ー個流程實例后,終端讀取流程實例對應(yīng)的流程定義,并將之轉(zhuǎn)換為流程圖。Socket服務(wù)能根據(jù)終端的請求將流程實例的各個節(jié)點的狀態(tài)傳輸給給終端,由終端在流程圖上將對應(yīng)節(jié)點根據(jù)不同狀態(tài)置為不同的顔色。6、流程日志如圖12所示為流程日志處理示意圖。一個流程實例執(zhí)行結(jié)束的流程引擎會產(chǎn)生ー個消息存放在隊列中,由入庫模塊將流程實例執(zhí)行的成功與否以及各節(jié)點執(zhí)行情況和時間保存到數(shù)據(jù)庫,相當(dāng)于記錄了流程的執(zhí)行軌跡,并將該流程實例從共享內(nèi)存中的空間釋放出來。流程入庫程序可以是多線程并行執(zhí)行,并且是在流程結(jié)束后才進行,而且實例和監(jiān)控區(qū)的共享內(nèi)存空間較大,可以是對多個流程的批量處理,所以如果配置合適,并且流程實例的執(zhí)行壓カ不是特別大的情況,基本不會形成性能瓶頸。關(guān)閉流程弓I擎將共享內(nèi)存中的所有數(shù)據(jù)落地到文件,重新啟動時則從文件上載回共享內(nèi)存,如果主機在流程實例未執(zhí)行完成的時候出現(xiàn)崩潰,則因共享內(nèi)存數(shù)據(jù)失去,流程實例數(shù)據(jù)將會丟失,這是ー種缺陷,但這是流程執(zhí)行效率和數(shù)據(jù)安全之間的ー種權(quán)衡的結(jié)果O本發(fā)明使用C++作為引擎核心的編寫語言,使用Lua作為腳本節(jié)點以及判斷節(jié)點的應(yīng)用,從程序執(zhí)行方面對性能進行了提高。流程引擎在執(zhí)行過程中對流程定義的讀取以及日志的保存如果都使用數(shù)據(jù)庫或者文件,會給性能帶來較大瓶頸,所以高效流程引擎使用共享內(nèi)存作為流程定義、流程實例、流程日志等的數(shù)據(jù)緩存,并使用其他模塊來對流程定義進行加載和日志的落地。高效流程引擎從各個方面提高了流程引擎的性能,經(jīng)過測試達到了業(yè)務(wù)系統(tǒng)對性能的要求。以上所述僅為本發(fā)明的較佳實施用例而已,并非用于限定本發(fā)明的保護范圖。凡在本發(fā)明的精神和原則之內(nèi),所作的任何修改、等同替換以及改進等,均應(yīng)包含在本發(fā)明的保護范圍之內(nèi)。權(quán)利要求1.高性能業(yè)務(wù)能力封裝流程引擎,其特征在于包括流程定義單元,用于生成規(guī)定流程各節(jié)點功能以及流程執(zhí)行規(guī)則的配置文件,所述流程由節(jié)點和節(jié)點間的關(guān)系組成;流程解析與加載單元,用于讀取流程定義單元的配置文件將其轉(zhuǎn)換為流程的對象且保存于內(nèi)存中;流程與節(jié)點的交互單元,用于執(zhí)行以規(guī)則為主線串接各個流程節(jié)點,對各個節(jié)點進行調(diào)用并與之交互,根據(jù)節(jié)點的返回結(jié)果通過判斷節(jié)點影響流程實例的執(zhí)行路線;流程執(zhí)行單元,用于根據(jù)流程定義創(chuàng)建對應(yīng)的流程實例時,在內(nèi)存中申請空間存放和維護流程變量、流程數(shù)據(jù)以及流程實例和各節(jié)點的狀態(tài)數(shù)據(jù);流程監(jiān)控單元,用于通過IPC訪問內(nèi)存中實例的節(jié)點狀態(tài)、執(zhí)行時間、流程變量值信息,并將其封裝為一系列查詢接口,通過網(wǎng)絡(luò)共同遠程監(jiān)控終端進行訪問;流程日志單元,用于通過消息機制觸發(fā)日志處理,采用多線程的并行處理方式將流程實例執(zhí)行的成功與否以及各節(jié)點執(zhí)行情況和時間保存到數(shù)據(jù)庫,并將該流程實例從共享內(nèi)存中的空間釋放出來。2.如權(quán)利要求I所述的高性能業(yè)務(wù)能力封裝流程引擎,其特征在于所述節(jié)點包括開始、結(jié)束、函數(shù)、腳本、狀態(tài)、分支、匯聚;所述節(jié)點間的關(guān)系包括前驅(qū)和后續(xù)。3.高性能業(yè)務(wù)能力封裝流程控制方法,其特征在于包括如下步驟生成規(guī)定流程各節(jié)點功能以及流程執(zhí)行規(guī)則的配置文件,所述流程由節(jié)點和節(jié)點間的關(guān)系組成;讀取流程定義單元的配置文件將其轉(zhuǎn)換為流程的對象且保存于內(nèi)存中;執(zhí)行以規(guī)則為主線串接各個流程節(jié)點,對各個節(jié)點進行調(diào)用并與之交互,根據(jù)節(jié)點的返回結(jié)果通過判斷節(jié)點影響流程實例的執(zhí)行路線;根據(jù)流程定義創(chuàng)建對應(yīng)的流程實例時,在內(nèi)存中申請空間存放和維護流程變量、流程數(shù)據(jù)以及流程實例和各節(jié)點的狀態(tài)數(shù)據(jù);通過IPC訪問內(nèi)存中實例的節(jié)點狀態(tài)、執(zhí)行時間、流程變量值信息,并將其封裝為一系列查詢接口,通過網(wǎng)絡(luò)共同遠程監(jiān)控終端進行訪問;通過消息機制觸發(fā)日志處理,采用多線程的并行處理方式將流程實例執(zhí)行的成功與否以及各節(jié)點執(zhí)行情況和時間保存到數(shù)據(jù)庫,并將該流程實例從共享內(nèi)存中的空間釋放出來。4.如權(quán)利要求3所述的高性能業(yè)務(wù)能力封裝流程控制方法,其特征在于所述節(jié)點包括開始、結(jié)束、函數(shù)、腳本、狀態(tài)、分支、匯聚;所述節(jié)點間的關(guān)系包括前驅(qū)和后續(xù)。全文摘要高性能業(yè)務(wù)能力封裝流程引擎及其流程控制方法,包括生成規(guī)定流程各節(jié)點功能以及流程執(zhí)行規(guī)則的配置文件;讀取流程定義單元的配置文件將其轉(zhuǎn)換為流程的對象且保存于內(nèi)存中;執(zhí)行以規(guī)則為主線串接各個流程節(jié)點,對各個節(jié)點進行調(diào)用并與之交互;在內(nèi)存中申請空間存放和維護流程變量、流程數(shù)據(jù)以及流程實例和各節(jié)點的狀態(tài)數(shù)據(jù);將內(nèi)存中實例的節(jié)點狀態(tài)、執(zhí)行時間、流程變量值信息,并將其封裝為一系列查詢接口,通過網(wǎng)絡(luò)共同遠程監(jiān)控終端進行訪問;通過消息機制觸發(fā)日志處理。本發(fā)明從各個方面提高了流程引擎的性能,經(jīng)過測試達到了業(yè)務(wù)系統(tǒng)對性能的要求。文檔編號G06F9/46GK102810070SQ201210246118公開日2012年12月5日申請日期2012年7月16日優(yōu)先權(quán)日2012年7月16日發(fā)明者王劍冰申請人:福建富士通信息軟件有限公司