Process Engine API和服務(wù)
API是與Flowable進(jìn)行交互的最常見(jiàn)的方式. 最主要的就是 ProcessEngine
, 從 ProcessEngine
中, 您可以獲取包含工作流程/BPM方法的各種服務(wù).
ProcessEngine
和服務(wù)對(duì)象是線程安全的, 所以你可以保留對(duì)整個(gè)服務(wù)器的引用.
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
ProcessEngines.getDefaultProcessEngine()
將在第一次被調(diào)用時(shí)初始化和構(gòu)建流程引擎, 并且總是返回相同的流程引擎. 正確創(chuàng)建和關(guān)閉所有流程引擎可以使用ProcessEngines.init()
和完成ProcessEngines.destroy()
.
該 ProcessEngines
類將掃描所有 flowable.cfg.xml
和 flowable-context.xml
文件. 對(duì)于 flowable.cfg.xml
文件, 流程引擎將以典型的Flowable方式構(gòu)建:
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()
對(duì)于所有的 flowable-context.xml
文件, 流程引擎都是以Spring的方式構(gòu)建的: 首先創(chuàng)建Spring應(yīng)用程序上下文, 然后從該應(yīng)用程序上下文獲取流程引擎.
該 RepositoryService
引擎工作時(shí)所需要的第一個(gè)服務(wù). 這項(xiàng)服務(wù)提管理流程倉(cāng)庫(kù)凭豪,例如部署最域,刪除驯绎,讀取流程資源等.
deployment
是Flowable引擎內(nèi)的包裝單位. deployment
可以包含多個(gè)BPMN 2.0 XML文件和任何其他資源. 包含在deployment
中的資源或文件選擇取決于開(kāi)發(fā)人員.
process definition
定義了一個(gè)流程中不同步驟的結(jié)構(gòu)和行為. 對(duì)于每個(gè)流程定義, 通常有許多實(shí)例同時(shí)運(yùn)行.
此外, 這項(xiàng)服務(wù)允許你:
- 查詢引擎已知的部署和流程定義.
- 暫停和激活整個(gè)部署或特定的流程定義. 暫停意味著不能對(duì)它們進(jìn)行下一步的操作, 而激活是相反的, 并且能夠再次進(jìn)行操作.
- 檢索各種資源, 例如引擎自動(dòng)生成的部署或流程中包含的文件.
- 檢索流程定義的POJO版本.
常用的流程定義文件擴(kuò)展名有:bpmn20.xml和bpmn. 流程定義的圖片一般用png格式.
RuntimeService
雖然 RepositoryService
主要是關(guān)于靜態(tài)信息, 但 RuntimeService
正好相反.
RuntimeService
主要用于管理流程在運(yùn)行時(shí)產(chǎn)生的數(shù)據(jù)(流程參數(shù), 事件, 流程實(shí)例, 以及執(zhí)行情況)以及對(duì)正在運(yùn)行的流程進(jìn)行操作的API.
系統(tǒng)用戶需要執(zhí)行的任務(wù)是Flowable等BPM引擎的核心. 而任務(wù)周圍的任務(wù)都被分組到TaskService中, 如:
- 查詢分配給用戶或組的任務(wù).
- 創(chuàng)建新的獨(dú)立任務(wù). 這些是與流程實(shí)例無(wú)關(guān)的任務(wù).
- 操作向哪個(gè)用戶分配任務(wù)或者哪個(gè)用戶以某種方式參與任務(wù).
- 聲稱和完成一項(xiàng)任務(wù). 聲稱意味著有人決參與任務(wù), 這也意味著該用戶將完成該任務(wù). 完成意味著完成任務(wù)的工作.
IdentityService
IdentityService
是非常簡(jiǎn)單的. 它支持組和用戶的管理(創(chuàng)建, 更新,
刪除, 查詢).
Flowable實(shí)際上不會(huì)在運(yùn)行時(shí)對(duì)用戶進(jìn)行任何檢查. 例如, 可以將任務(wù)分配給任何用戶, 但是引擎不驗(yàn)證該用戶是否被系統(tǒng)知曉. 這是意味著Flowable引擎也可以與LDAP, Active Directory等服務(wù)結(jié)合使用.
FormService
FormService
是一個(gè)可選的服務(wù). 該服務(wù)引入了開(kāi)始表和任務(wù)表的概念. 開(kāi)始形式是流程實(shí)例啟動(dòng)前顯示給用戶的一種形式, 而任務(wù)形式是當(dāng)一個(gè)用戶要填寫(xiě)一份表的時(shí)候進(jìn)行顯示.
HistoryService
HistoryService
服務(wù)公開(kāi)有關(guān)正在進(jìn)行和歷史進(jìn)程實(shí)例的信息.
這與運(yùn)行時(shí)信息不同, 因?yàn)榇诉\(yùn)行時(shí)信息僅在任何特定時(shí)刻包含實(shí)際運(yùn)行時(shí)狀態(tài), 并且針對(duì)運(yùn)行時(shí)進(jìn)程執(zhí)行性能進(jìn)行了優(yōu)化. 歷史信息(誰(shuí)做了哪些任務(wù), 完成任務(wù)需要多長(zhǎng)時(shí)間, 每個(gè)流程實(shí)例遵循哪條路徑, 等等)經(jīng)過(guò)優(yōu)化, 易于查詢, 并且永久保存.
ManagementService
ManagementService
為流程引擎上的管理和維護(hù)操作提供服務(wù). 此外, 它還暴露了查詢功能和作業(yè)管理操作. 作業(yè)在Flowable中用于各種事情, 如定時(shí)器, 異步延續(xù), 延遲掛起/激活等等.
DynamicBpmnService
DynamicBpmnService
可以用來(lái)改變流程定義的一部分, 而無(wú)需重新部署. 例如, 可以在流程定義中更改用戶任務(wù)的受理人或者更改服務(wù)任務(wù)的類名稱.
異常
FlowableWrongDbException: 當(dāng)Flowable引擎發(fā)現(xiàn)數(shù)據(jù)庫(kù)模式版本和引擎版本之間不匹配時(shí)拋出.
FlowableOptimisticLockingException: 在同一數(shù)據(jù)項(xiàng)的并發(fā)訪問(wèn)導(dǎo)致數(shù)據(jù)存儲(chǔ)區(qū)發(fā)生樂(lè)觀鎖時(shí)拋出.
FlowableClassLoadingException: 當(dāng)沒(méi)有找到請(qǐng)求加載的類時(shí)或加載時(shí)發(fā)生錯(cuò)誤(例如JavaDelegates, TaskListeners, ...)時(shí)拋出.
FlowableObjectNotFoundException: 當(dāng)一個(gè)被請(qǐng)求或被執(zhí)行的對(duì)象不存在時(shí)拋出.
FlowableIllegalArgumentException: 表示在Flowable API調(diào)用中提供了非法參數(shù)的異常, 在引擎配置中配置了非法值, 或者提供了非法值,
或者在進(jìn)程定義中使用了非法值.
FlowableTaskAlreadyClaimedException: 當(dāng)一個(gè)任務(wù)已經(jīng)被聲明,taskService.claim(…?)被調(diào)用的時(shí)候拋出.
查詢API
查詢引擎有兩種方式: 查詢API和SQL查詢.
查詢API允許您使用API編程來(lái)安全的查詢. 您可以為查詢添加各種條件(所有這些條件都作為邏輯“與”一起應(yīng)用).以下代碼顯示了一個(gè)示例:
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee("kermit")
.processVariableValueEquals("orderId", "0815")
.orderByDueDate().asc()
.list();
有時(shí)您需要更強(qiáng)大的查詢, 例如使用 OR
運(yùn)算符的查詢或使用查詢API無(wú)法表達(dá)的約束.
對(duì)于這些情況, 我們有SQL查詢, 它允許您編寫(xiě)自己的SQL查詢. 返回類型由您使用的Query對(duì)象定義, 數(shù)據(jù)映射到正確的對(duì)象(Task, ProcessInstance, Execution, ...).
由于查詢將在數(shù)據(jù)庫(kù)中被觸發(fā), 因此必須使用數(shù)據(jù)庫(kù)中定義的表名和列名稱; 這需要一些有關(guān)內(nèi)部數(shù)據(jù)結(jié)構(gòu)的知識(shí), 建議小心使用SQL查詢. 表名可以通過(guò)API檢索, 以保持依賴性盡可能小.
List<Task> tasks = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) +
" T WHERE T.NAME_ = #{taskName}")
.parameter("taskName", "gonzoTask")
.list();
long count = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, " +
managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID_ = T1.ID_")
.count();
變量
每個(gè)流程實(shí)例都需要使用數(shù)據(jù)來(lái)執(zhí)行它所組成的步驟.
在Flowable中, 這個(gè)數(shù)據(jù)被稱為變量, 它們被存儲(chǔ)在數(shù)據(jù)庫(kù)中. 在調(diào)用外部服務(wù)時(shí), 變量可以用在表達(dá)式中(例如, 在專用網(wǎng)關(guān)中選擇正確的傳出序列流).
流程實(shí)例可以包含變量(稱為流程變量), 也可以包含執(zhí)行用戶任務(wù)時(shí)包含的變量. 一個(gè)流程實(shí)例可以有任意數(shù)量的變量. 每個(gè)變量都存儲(chǔ)在ACT_RU_VARIABLE
數(shù)據(jù)庫(kù)表中的一行.
所有 startProcessInstanceXXX
方法都有一個(gè)可選參數(shù), 用于在創(chuàng)建和啟動(dòng)流程實(shí)例時(shí)提供變量.
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
變量可以在流程執(zhí)行過(guò)程中添加
void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);
變量也可以被檢索, 如下所示. 請(qǐng)注意, TaskService
上存在類似的方法. 這意味著任務(wù)(如執(zhí)行)可以具有僅在任務(wù)期間處于活動(dòng)狀態(tài)的局部變量.
Map<String, Object> getVariables(String executionId);
Map<String, Object> getVariablesLocal(String executionId);
Map<String, Object> getVariables(String executionId, Collection<String> variableNames);
Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames);
Object getVariable(String executionId, String variableName);
<T> T getVariable(String executionId, String variableName, Class<T> variableClass);
瞬態(tài)變量
瞬態(tài)變量是像變量一樣的變量, 但不會(huì)被持久化.
以下內(nèi)容適用于瞬態(tài)變量:
- 對(duì)于瞬態(tài)變量沒(méi)有存儲(chǔ)歷史.
- 瞬態(tài)變量只能由setTransientVariable(name,value)設(shè)置, 但是在調(diào)用getVariable(name)時(shí)也會(huì)返回瞬態(tài)變量, 其原因是為了使表達(dá)式的寫(xiě)作變得容易, 并且使用變量的現(xiàn)有邏輯適用于這兩種類型.
- 一個(gè)瞬態(tài)變量會(huì)隱藏一個(gè)具有相同名稱的流程變量. 這意味著, 如果在流程實(shí)例上設(shè)置了流程變量和瞬態(tài)變量, 并調(diào)用
getVariable("someVariable")
, 則將返回瞬態(tài)變量值. - 流程變量只能在流程定義中的下一個(gè)等待狀態(tài)之前被訪問(wèn). 這里, 等待狀態(tài)意就是流程實(shí)例中保存數(shù)據(jù)的點(diǎn).
您可以在常規(guī)變量暴露的大多數(shù)地方設(shè)置和獲取瞬態(tài)變量:
- DelegateExecution 在 JavaDelegate 實(shí)現(xiàn)
- DelegateExecution 在 ExecutionListener 實(shí)現(xiàn)和DelegateTask上的TaskListener實(shí)現(xiàn)
- 在通過(guò)執(zhí)行對(duì)象的腳本任務(wù)中
- 通過(guò)運(yùn)行時(shí)服務(wù)啟動(dòng)流程實(shí)例時(shí)
- 完成任務(wù)時(shí)
- 調(diào)用runtimeService.trigger方法時(shí)
表達(dá)式
Flowable使用UEL進(jìn)行表達(dá)式解析. UEL代表統(tǒng)一表達(dá)式語(yǔ)言(Unified Expression Language).
值表達(dá)式: 解析為一個(gè)值. 默認(rèn)情況下, 所有的過(guò)程變量都可以使用.
$ {myVar}
$ {myBean.myProperty}
方法表達(dá)式: 調(diào)用帶或不帶參數(shù)的方法. 當(dāng)調(diào)用一個(gè)沒(méi)有參數(shù)的方法時(shí), 一定要在方法名之后加上空的圓括號(hào). 傳遞的參數(shù)可以是字面值或自己解析的表達(dá)式.
$ {printer.print()}
$ {myBean.addNewOrder('orderName')}
$ {myBean.doSomething(myVar,execution)}
在所有的流程變量之上, 有幾個(gè)可以在表達(dá)式中使用的默認(rèn)對(duì)象:
execution: DelegateExecution
持有關(guān)于持續(xù)執(zhí)行的附加信息.
task: DelegateTask
持有關(guān)于當(dāng)前任務(wù)的附加信息. 注意: 只適用于任務(wù)監(jiān)聽(tīng)器評(píng)估的表達(dá)式.
authenticatedUserId: 當(dāng)前通過(guò)身份驗(yàn)證的用戶的ID. 如果沒(méi)有用戶通過(guò)身份驗(yàn)證, 該變量不可用.
Web應(yīng)用程序中的流程引擎
這個(gè) ProcessEngine
是一個(gè)線程安全的類, 可以很容易地在多個(gè)線程之間共享. 在Web應(yīng)用程序中, 這意味著可以在容器啟動(dòng)時(shí)創(chuàng)建一次流程引擎坊萝,并在容器關(guān)閉時(shí)關(guān)閉引擎.
下面的代碼片斷展示了如何編寫(xiě)一個(gè)簡(jiǎn)單的 ServletContextListener
在簡(jiǎn)單的Servlet環(huán)境中初始化和銷毀??流程引擎:
public class ProcessEnginesServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
ProcessEngines.init();
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ProcessEngines.destroy();
}
}
該 contextInitialized
方法將委托給 ProcessEngines.init()
. 這將 flowable.cfg.xml
在類路徑中查找資源文件, 并創(chuàng)建一個(gè)ProcessEngine
. 如果在類路徑中有多個(gè)這樣的資源文件, 請(qǐng)確保它們都有不同的名稱.
當(dāng)需要流程引擎時(shí), 可以使用以下方法獲取流程引擎:
ProcessEngines.getDefaultProcessEngine()
或
ProcessEngines.getProcessEngine("myName");