項目實踐之工作流引擎基本文檔!Activiti工作流框架之流程引擎API和服務詳解
流程引擎的API和服務
流程引擎API(ProcessEngine API)是與Activiti打交道的最常用方式
Activiti從ProcessEngine開始.在ProcessEngine中,可以獲得很多包括工作流或者BPM方法的服務
ProcessEngine和服務類都是線程安全的.可以在整個服務器中僅保持它們的一個引用就可以
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();
ProcessEngines.getDefaultProcessEngine(): - 會在第一次調用時,初始化并創建一個流程引擎,以后再調用就會返回相同的流程引擎 - 使用對應的方法可以創建和關閉所有流程引擎:ProcessEngines.init()和ProcessEngines.destroy() - ProcessEngines會掃描所有activiti.cfg.xml 和 activiti-context.xml 文件 - 對于activiti.cfg.xml文件,流程引擎會使用Activiti的經典方式構建: - ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine() - 對于activiti-context.xml文件,流程引擎會使用Spring方法構建:先創建一個Spring的環境,然后通過環境獲得流程引擎 - 所有服務都是無狀態的.這意味著可以在多節點集群環境下運行Activiti,每個節點都指向同一個數據庫,不用擔心哪個機器實際執行前端的調用.無論在哪里執行服務都沒有問題 RepositoryService - 負責靜態信息 - 是使用Activiti引擎時最先接觸的服務,提供了管理和控制發布包和流程定義的操作 - 流程定義是BPMN 2.0流程的java實現.它包含了一個流程每個環節的結構和行為 - 發布包是Activiti引擎的打包單位.一個發布包可以包含多個BPMN 2.0 xml文件和其他資源 - 開發者可以自由選擇把任意資源包含到發布包中 - 既可以把一個單獨的BPMN 2.0 xml文件放到發布包里,也可以把整個流程和相關資源都放在一起 - 可以通過RepositoryService來部署這種發布包.發布一個發布包,意味著把它上傳到引擎中,所有流程都會在保存進數據庫之前分析解析好 - 從這點來說,系統知道這個發布包的存在,發布包中包含的流程就已經可以啟動了 - RepositoryService可以查詢引擎中的發布包和流程定義 - RepositoryService暫停或激活發布包,對應全部和特定流程定義.暫停意味著它們不能再執行任何操作了,激活是對應的反向操作 - RepositoryService獲得多種資源,例如包含在發布包里的文件,引擎自動生成的流程圖 - RepositoryService獲得流程定義的pojo版本,可以用來通過java解析流程,而不必通過xml RuntimeService - 負責啟動一個流程定義的新實例 - 流程定義定義了流程各個節點的結構和行為 - 流程實例就是這樣一個流程定義的實例 - 對每個流程定義來說,同一時間會有很多實例在執行 - RuntimeService可以用來獲取和保存流程變量,這些數據是特定于某個流程實例的,并會被很多流程中的節點使用 - Runtimeservice可以查詢流程實例和執行,執行對應BPMN 2.0中的'token',基本上執行指向流程實例當前在哪里 - RuntimeService可以在流程實例等待外部觸發時使用,可以用來繼續流程實例.流程實例可以有很多暫停狀態,而服務提供了多種方法來'觸發'實例, 接受外部觸發后,流程實例就會繼續向下執行 TaskService - 任務是由系統中真實人員執行的,它是Activiti這類BPMN引擎的核心功能之一, 所有與任務有關的功能都包含在TaskService中 - 在TaskService中,查詢分配給用戶或組的任務 - 在TaskService中,創建獨立運行任務,這些任務與流程實例無關 - 在TaskService中,手工設置任務的執行者,或者這些用戶通過何種方式與任務關聯 - 在TaskService中,認領并完成一個任務: - 認領意味著一個人期望成為任務的執行者,即這個用戶會完成這個任務 - 完成意味著“做這個任務要求的事情”,通常來說會有很多種處理形式 IdentityService - 可以管理,創建,更新,刪除,查詢..群組和用戶 - Activiti執行時并沒有對用戶進行檢查.任務可以分配給任何人,但是引擎不會校驗系統中是否存在這個用戶.這是Activiti引擎也可以使用外部服務:ldap,活動目錄... HistoryService - HistoryService提供了Activiti引擎的所有歷史數據 - 在執行流程時,引擎會根據配置保存很多數據:流程實例啟動時間,任務的參與者,完成任務的時間,每個流程實例的執行路徑..., 這個服務主要通過查詢功能來獲得這些數據 FormService - FormService是一個可選服務,即使不使用它,Activiti也可以完美運行,不會損失任何功能 - FormService提供了啟動表單和任務表單兩個概念 - 啟動表單會在流程實例啟動之前展示給用戶 - 任務表單會在用戶完成任務時展示 - Activiti支持在BPMN 2.0流程定義中設置這些表單.這個服務以一種簡單的方式將數據暴露出來,是可選的,表單也不一定要嵌入到流程定義中 ManagementService - 在使用Activiti的定制環境中基本上不會用到 - ManagementService可以查詢數據庫的表和表的元數據 - ManagementService提供了查詢和管理異步操作的功能 - Activiti的異步操作用途很多:定時器,異步操作,延遲暫停,激活..
異常策略
Activiti中的基礎異常為org.activiti.engine.ActivitiException, 一個非檢查異常
這個異常可以在任何時候被API拋出,特定方法拋出的特定的異常
/** * Called when the task is successfully executed. * @param taskId the id of the task to complete, cannot be null. * @throws ActivitiObjectNotFoundException when no task exists with the given id. */ void complete(String taskId);
當傳入一個不存在的任務的id時,就會拋出異常.taskId不能為null,如果傳入null,就會拋出ActivitiIllegalArgumentException
應該避免過多的異常繼承,子類只用于特定的場合
流程引擎和API調用的其他場合不使用子類異常,拋出一個普通的ActivitiExceptions
ActivitiWrongDbException: 當Activiti引擎發現數據庫版本號和引擎版本號不一致時拋出 ActivitiOptimisticLockingException: 對同一數據進行并發方法并出現樂觀鎖時拋出 ActivitiClassLoadingException: 當無法找到需要加載的類或在加載類時出現了錯誤-JavaDelegate,TaskListener ActivitiObjectNotFoundException: 當請求或操作的對應不存在時拋出 ActivitiIllegalArgumentException: 這個異常表示調用Activiti API時傳入了一個非法的參數,可能是引擎配置中的非法值,或提供了一個非法值,或流程定義中使用的非法值 ActivitiTaskAlreadyClaimedException: 當任務已經被認領了,再調用taskService.claim(...)就會拋出
查詢 API
在Activiti流程引擎中查詢數據有兩種方式:
查詢API
原生查詢
查詢API: 查詢API提供了完全類型安全的API,可以自定義添加查詢條件和精確的排序條件,所有條件都以AND組合
List
原生查詢:
需要更強大的查詢時:使用OR條件或者能使用查詢API實現的條件.
可以編寫自己的SQL查詢. 返回類型由你使用的查詢對象決定,數據會映射到正確的對象上:任務,流程實例,執行…
查詢作用在數據庫上,必須使用數據庫中定義的表名和列名,要了解內部數據結構
使用原生查詢時,表名可以通過API獲得,可以盡量減少對數據庫的依賴
List
表達式
Activiti使用UEL處理表達式.UEL即統一表達式語言, 是EE6規范的一部分.為了在所有運行環境都支持最新UEL的所有功能,使用JUEL的修改版本
表達式可以用在很多場景下:
Java服務任務
執行-
任務-
條件流
雖然有兩重表達式:值表達式和方法表達式, Activiti進行了抽象,所以兩者可以同樣使用在需要表達式的場景中
Value expression: 解析為值,默認
${myVar} ${myBean.myProperty}
所有流程變量都可以使用,所有spring bean(spring環境中)也可以使用在表達式中
Method expression: 調用一個方法,使用或不使用參數
${printer.print()} ${myBean.addNewOrder('orderName')} ${myBean.doSomething(myVar, execution)}
當調用一個無參數的方法時,記得在方法名后添加空的括號,以區分值表達式
傳遞的參數可以是字符串也可以是表達式,它們會被自動解析
這些表達式支持解析原始類型:
bean
list
數組
map
包括比較
在流程實例中,表達式中可以使用一些默認對象:
execution: DelegateExecution,提供外出執行的額外信息
task: DelegateTask,提供當前任務的額外信息 ,只對任務-的表達式有效
authenticatedUserId: 當前登錄的用戶id.如果沒有用戶登錄,這個變量就不可用
單元測試
業務流程是軟件項目的一部分,它也應該和普通的業務流程一樣進行測試:使用單元測試
因為Activiti是一個嵌入式的java引擎,所以為業務流程編寫單元測試和寫普通單元測試完全一樣
Activiti支持JUnit 3和4進行單元測試
使用JUnit 3時, 必須集成org.activiti.engine.test.ActivitiTestCase. 它通過保護的成員變量提供ProcessEngine和服務,
在測試的setup()中,默認會使用classpath下的activiti.cfg.xml初始化流程引擎
要使用不同的配置文件,可以重寫getConfigurationResource() 方法
如果配置文件相同的話,對應的流程引擎會被靜態緩存,就可以用于多個單元測試
繼承了ActivitiTestCase, 可以在測試方法上使用org.activiti.engine.test.Deployment注解.測試執行前,與測試類在同一個包下的,格式為testClassName.testMethod.bpmn20.xml的資源文件,會被部署.測試結束后,發布包也會被刪除,包括所有相關的流程實例,任務…Deployment注解也可以直接設置資源的位置
public class MyBusinessProcessTest extends ActivitiTestCase { @Deployment public void testSimpleProcess() { runtimeService.startProcessInstanceByKey("simpleProcess"); Task task = taskService.createTaskQuery().singleResult(); assertEquals("My Task", task.getName()); taskService.complete(task.getId()); assertEquals(0, runtimeService.createProcessInstanceQuery().count()); } }
要想在使用JUnit 4編寫單元測試時獲得同樣的功能
可以使用org.activiti.engine.test.ActivitiRule. 通過它,可以通過getter方法獲得流程引擎和各種服務
使用這個Rule也會啟用org.activiti.engine.test.Deployment注解
它會在classpath下查找默認的配置文件,如果配置文件相同的話,對應的流程引擎會被靜態緩存,就可以用于多個單元測試
public class MyBusinessProcessTest { @Rule public ActivitiRule activitiRule = new ActivitiRule(); @Test @Deployment public void ruleUsageExample() { RuntimeService runtimeService = activitiRule.getRuntimeService(); runtimeService.startProcessInstanceByKey("ruleUsage"); TaskService taskService = activitiRule.getTaskService(); Task task = taskService.createTaskQuery().singleResult(); assertEquals("My Task", task.getName()); taskService.complete(task.getId()); assertEquals(0, runtimeService.createProcessInstanceQuery().count()); } }
調試單元測試
使用內存數據庫H2進行單元測試,在調試環境監視Activiti的數據庫:
在單元測試里設置了一個斷點:
用調試模式運行單元測試,右擊單元測試,選擇[運行為]和[單元測試],測試會停在我們的斷點上, 然后我們就可以監視測試的變量,它們顯示在調試面板里
要監視Activiti的數據,打開[顯示]窗口(如果找不到,打開[窗口]-[顯示視圖]-[其他],選擇[顯示]并點擊[代碼已完成],org.h2.tools.Server.createWebServer("-web").start()
選擇你點擊的行,右擊.然后選擇[顯示]
打開一個瀏覽器,輸入http://localhost:8082, 輸入內存數據庫的JDBC URL(默認為jdbc:h2:mem:activiti),點擊連接按鈕
可以看到Activiti的數據,通過它們可以了解單元測試時,如何以及為什么這樣運行的
Web中的流程引擎
ProcessEngine是線程安全的,可以在多線程下共享
在web應用中, 意味著可以在容器啟動時創建流程引擎, 在容器關閉時關閉流程引擎
編寫一個ServletContextListener 在普通的Servlet環境下初始化和銷毀流程引擎:
public class ProcessEnginesServletContextListener implements ServletContextListener { public void contextInitialized(ServletContextEvent servletContextEvent) { ProcessEngines.init(); } public void contextDestroyed(ServletContextEvent servletContextEvent) { ProcessEngines.destroy(); } }
contextInitialized方法會執行ProcessEngines.init() 這會查找classpath下的activiti.cfg.xml文件,根據配置文件創建一個ProcessEngine(比如,多個jar中都包含配置文件)如果classpath中包含多個配置文件,確認它們有不同的名字
需要使用流程引擎時,可以通過
ProcessEngines.getDefaultProcessEngine()
或
ProcessEngines.getProcessEngine("myName");
ContextListener中的contextDestroyed方法會執行ProcessEngines.destroy().這會關閉所有初始化的流程引擎
API Servlet XML
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。