最近開(kāi)始接觸JBPM4,網(wǎng)上關(guān)于JBPM4的資料少之又少。大多是關(guān)于JBPM3的。而4跟3的API差異也較大。在學(xué)習(xí)過(guò)程中做了一點(diǎn)關(guān)于JBPM4的筆記。強(qiáng)烈期望JBPM4達(dá)人能貢獻(xiàn)一些JBPM4方面的學(xué)習(xí)資料或視頻教程或出版發(fā)行JBPM4的書(shū)籍之類的。
本文電子版下載
流程定義引擎:
ProcessEngine processEngine;
獲取:
processEngine=Configuration.getProcessEngine(); |
重要的幾個(gè)接口:
RepositoryService repositoryService; ExecutionService executionService; TaskService taskService; HistoryService historyService; ManagementService managementService; |
獲取:
repositoryService=processEngine.getRepositoryService(); executionService=processEngine.getExecutionService(); taskService=processEngine.getTaskService(); historyService=processEngine.getHistoryService(); managementService=processEngine.getManagementService(); |
說(shuō)明:
RepositoryService主要用來(lái)管理和發(fā)布流程定義,發(fā)布流程定義、刪除流程定義、查看流程定義。
流程定義發(fā)布:
repositoryService.createDeployment().addResourceFromClasspath("demo.jpdl.xml").deploy(); |
注:此方法表示從classpath路徑加載一個(gè)流程定義文件,并發(fā)布,上例中demo.jpdl.xml文件位于src(classpath)路徑下,若流程定義文件放置與包中,則需要使用包名+jpdl文件名。如com/jbpm/demo.jpdl.xml
查看流程定義:
repositoryService.createDeployment().addResourceFromClasspath("test1.jpdl.xml").deploy(); List<ProcessDefinition> list=repositoryService.createProcessDefinitionQuery().list(); for (ProcessDefinition processDefinition : list) { System.out.println("流程定義Id:"+processDefinition.getId()); System.out.println("流程部署Id:"+processDefinition.getDeploymentId()); } |
刪除流程定義:
String deploymentId=repositoryService.createDeployment().addResourceFromClasspath("test1.jpdl.xml").deploy(); repositoryService.deleteDeploymentCascade(deploymentId); |
deploymentId為流程定義部署Id
ExecutionService主要用來(lái)操作流程實(shí)例,啟動(dòng)流程實(shí)例、查看流程實(shí)例、刪除流程實(shí)例、結(jié)束流程實(shí)例。
其前提條件是發(fā)布了流程定義
啟動(dòng)流程實(shí)例:
repositoryService.createDeployment().addResourceFromClasspath("demo.jpdl.xml").deploy(); ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo"); |
使用executionService.startProcessInstanceByKey("demo");方法來(lái)啟動(dòng)一個(gè)流程實(shí)例。其中startProcessInstanceByKey就表示以key的方式來(lái)啟動(dòng)流程實(shí)例,key為流程定義文件中process節(jié)點(diǎn)的key屬性,若未明確給出key屬性,則默認(rèn)key屬性的值與name屬性的值相同。
同樣也可以使用executionService.startProcessInstanceById(processDefinitionId)的方式來(lái)啟動(dòng)流程實(shí)例。此方法是用流程定義文件中process節(jié)點(diǎn)的id屬性來(lái)啟動(dòng)流程實(shí)例。
其Id屬性由兩部分組成流程定義的key和流程定義的版本來(lái)組成。形如key-version
例如:
ProcessInstance processInstance=executionService.startProcessInstanceById("demo-1");
其中demo-1就為流程定義中的流程Id,其key為demo,版本號(hào)為1
同樣使用此方法可用來(lái)啟動(dòng)指定版本號(hào)的流程實(shí)例。
查看流程實(shí)例:
List<ProcessInstance> list=executionService.createProcessInstanceQuery().list(); for (ProcessInstance processInstance : list) { System.out.println("流程實(shí)例Id:"+processInstance.getId()); System.out.println("流程定義Id:"+processInstance.getProcessDefinitionId()); } |
級(jí)聯(lián)刪除流程實(shí)例:
executionService.deleteProcessInstanceCascade(processInstance.getId()); |
結(jié)束流程實(shí)例:
executionService.endProcessInstance(processInstance.getId(), "結(jié)束流程實(shí)例"); |
注意:在使用executionService.endProcessInstance()對(duì)流程實(shí)例進(jìn)行結(jié)束操作后,需要重新查詢processInstance才能得到更新后的流程實(shí)例,如果流程已結(jié)束,則查詢結(jié)果為null
如:
executionService.endProcessInstance(processInstance.getId(), "結(jié)束流程實(shí)例"); System.out.println(processInstance.isEnded()); 此行代碼是無(wú)意義的,因?yàn)榇藭r(shí)并未獲取到更新后的流程實(shí)例,需要重新查詢流程實(shí)例,所以此處返回為false System.out.println("-----------查詢流程實(shí)例--------------->"); List<ProcessInstance> list=executionService.createProcessInstanceQuery().list(); for (ProcessInstance processInstance : list) { System.out.println("流程實(shí)例Id:"+processInstance.getId()); System.out.println("流程定義Id:"+processInstance.getProcessDefinitionId()); } |
結(jié)果:
false
-----------查詢流程實(shí)例--------------->
使流程向下執(zhí)行:
在使用executionService啟動(dòng)流程實(shí)例后,流程會(huì)順著向下執(zhí)行(即啟動(dòng)流程實(shí)例后,流程會(huì)從start節(jié)點(diǎn)向下移動(dòng)),在state或task節(jié)點(diǎn),流程會(huì)暫停下來(lái),滿足條件后流程會(huì)向下繼續(xù)執(zhí)行,直到流程end節(jié)點(diǎn),結(jié)束流程。
在程序中是流程遵循某一條件,沿著某個(gè)方向流動(dòng)的方法為executionService.signalExecutionById();
該方法有多個(gè)重載:
ProcessInstance signalExecutionById(String executionId); //若在流程定義某一個(gè)節(jié)點(diǎn)沒(méi)有分支時(shí)(只有一個(gè)transition時(shí)),調(diào)用此方法,可將流程繼續(xù)向下執(zhí)行 executionId為流程實(shí)例Id ProcessInstance signalExecutionById(String executionId, String signalName); //若在流程定義某一個(gè)節(jié)點(diǎn)有多個(gè)分支時(shí)(有多個(gè)transition時(shí)),調(diào)用此方法,可將流程沿著transition所指的方向向下執(zhí)行 executionId為流程實(shí)例Id, signalName為流程定義中transition節(jié)點(diǎn)的name屬性的值 ProcessInstance signalExecutionById(String executionId, String signalName, Map<String, ?> parameters); 用于將流程沿著signalName方向(transition的name屬性所指的方向)向下繼續(xù)執(zhí)行,在執(zhí)行的過(guò)程中順便傳遞參數(shù)parameters ProcessInstance signalExecutionById(String executionId, Map<String, ?> parameters); 用于將流程向下繼續(xù)執(zhí)行,在執(zhí)行的過(guò)程中順便傳遞參數(shù)parameters |
注:當(dāng)一個(gè)節(jié)點(diǎn)有多個(gè)分支時(shí),若要通過(guò)signalExecutionById()方法將流程向下執(zhí)行必須明確指出signalName即(transition的name屬性所指的方向),否則流程不會(huì)向下執(zhí)行,仍會(huì)停留在當(dāng)前節(jié)點(diǎn)。因?yàn)?/span>jbpm不確定流程該流向那個(gè)方向。
示例代碼:
1. 沒(méi)有分支的state流向
流程定義文件:
<?xmlversion="1.0"encoding="UTF-8"?> <processname="demo"xmlns="http://jbpm.org/4.3/jpdl"> <startname="start"g="87,113,48,48"> <transitionname="to state"to="state"g="-53,-17"/> </start> <statename="state"g="238,236,92,52"> <transitionname="to end"to="end"g="-41,-17"/> </state> <endname="end"g="384,367,48,48"/> </process> |
測(cè)試代碼:
import org.jbpm.api.Configuration; import org.jbpm.api.ExecutionService; import org.jbpm.api.ProcessEngine; import org.jbpm.api.ProcessInstance; import org.jbpm.api.RepositoryService; import junit.framework.TestCase; publicclass DemoTest extends TestCase{ ProcessEngine processEngine; RepositoryService repositoryService; ExecutionService executionService; @Override protectedvoid setUp() throws Exception { processEngine=Configuration.getProcessEngine(); repositoryService=processEngine.getRepositoryService(); executionService=processEngine.getExecutionService(); //部署流程定義 repositoryService.createDeployment().addResourceFromClasspath("demo.jpdl.xml").deploy(); } publicvoid testProcessInstance(){ ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo"); System.out.println("流程實(shí)例Id:"+processInstance.getId()); System.out.println("流程定義Id:"+processInstance.getProcessDefinitionId()); //判斷當(dāng)前是否位于start節(jié)點(diǎn) System.out.println("是否位于start節(jié)點(diǎn):"+processInstance.isActive("start")); //判斷當(dāng)前是否位于state節(jié)點(diǎn) System.out.println("是否位于state節(jié)點(diǎn):"+processInstance.isActive("state")); //判斷流程是否結(jié)束 System.out.println("判斷流程是否結(jié)束:"+processInstance.isEnded()); System.out.println("------------------------>使流程繼續(xù)向下執(zhí)行"); //使流程繼續(xù)向下執(zhí)行 //ProcessInstance instanceState=executionService.signalExecutionById(processInstance.getId()); //此處也可以這么寫 ProcessInstance instanceState=executionService.signalExecutionById(processInstance.getId(),"to end"); //to end為流程定義中用于連接state和end節(jié)點(diǎn)之間transition的name屬性的值 //判斷當(dāng)前是否位于state節(jié)點(diǎn) System.out.println("是否位于state節(jié)點(diǎn):"+instanceState.isActive("state")); //判斷流程是否結(jié)束 System.out.println("判斷流程是否結(jié)束:"+instanceState.isEnded()); } } |
執(zhí)行結(jié)果:
流程實(shí)例Id:demo1.7 流程定義Id:demo1-1 是否位于start節(jié)點(diǎn):false 是否位于state節(jié)點(diǎn):true 判斷流程是否結(jié)束:false ------------------------>使流程繼續(xù)向下執(zhí)行 是否位于state節(jié)點(diǎn):false 判斷流程是否結(jié)束:true |
2. 含有分支的state流向
流程定義文件:
<?xmlversion="1.0"encoding="UTF-8"?> <processname="demo"xmlns="http://jbpm.org/4.3/jpdl"> <startg="347,27,48,48"name="start"> <transitiong="-53,-17"name="to state"to="state"/> </start> <stateg="329,132,92,52"name="state"> <transitionname="to 200"to="200"g="-41,-17"/> <transitionname="to 400"to="400"g="-41,-17"/> </state> <endg="358,321,48,48"name="end"/> <statename="200"g="420,226,92,52"> <transitionname="to end"to="end"g="-41,-17"/> </state> <statename="400"g="266,225,92,52"> <transitionname="to end"to="end"g="-41,-17"/> </state> </process> |
測(cè)試代碼:
import junit.framework.TestCase; public class Demo2Test extends TestCase{ ProcessEngine processEngine; RepositoryService repositoryService; ExecutionService executionService; @Override protected void setUp() throws Exception { processEngine=Configuration.getProcessEngine(); repositoryService=processEngine.getRepositoryService(); executionService=processEngine.getExecutionService(); //部署流程定義 repositoryService.createDeployment().addResourceFromClasspath("demo.jpdl.xml").deploy(); } public void testProcessInstance(){ ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo"); System.out.println("流程實(shí)例Id:"+processInstance.getId()); System.out.println("流程定義Id:"+processInstance.getProcessDefinitionId()); //判斷當(dāng)前是否位于start節(jié)點(diǎn) System.out.println("是否位于start節(jié)點(diǎn):"+processInstance.isActive("start")); //判斷當(dāng)前是否位于state節(jié)點(diǎn) System.out.println("是否位于state節(jié)點(diǎn):"+processInstance.isActive("state")); //判斷流程是否結(jié)束 System.out.println("判斷流程是否結(jié)束:"+processInstance.isEnded()); System.out.println("------------------------>使流程繼續(xù)向下執(zhí)行"); //不明確指出流動(dòng)方向,看流程位于那個(gè)節(jié)點(diǎn) ProcessInstance instance=executionService.signalExecutionById(processInstance.getId()); //判斷當(dāng)前是否位于state節(jié)點(diǎn) System.out.println("是否位于state節(jié)點(diǎn):"+instance.isActive("state")); //判斷流程是否結(jié)束 System.out.println("判斷流程是否結(jié)束:"+instance.isEnded()); } } |
執(zhí)行結(jié)果:
流程實(shí)例Id:demo.7 流程定義Id:demo-1 是否位于start節(jié)點(diǎn):false 是否位于state節(jié)點(diǎn):true 判斷流程是否結(jié)束:false ------------------------>使流程繼續(xù)向下執(zhí)行 是否位于state節(jié)點(diǎn):true 判斷流程是否結(jié)束:false |
指明流向節(jié)點(diǎn):
ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo"); System.out.println("------------------------>使流程繼續(xù)向下執(zhí)行"); System.out.println("------------------------>使流程流向200"); ProcessInstance processInstance200=executionService.signalExecutionById(processInstance.getId(), "to 200"); System.out.println("當(dāng)前流程是否位于200節(jié)點(diǎn)---->"+processInstance200.isActive("200")); System.out.println("當(dāng)前流程是否結(jié)束---->"+processInstance200.isEnded()); /*System.out.println("------------------------>使流程流向400"); ProcessInstance processInstance400=executionService.signalExecutionById(processInstance.getId(), "to 400"); System.out.println("當(dāng)前流程是否位于400節(jié)點(diǎn)---->"+processInstance400.isActive("400")); System.out.println("當(dāng)前流程是否結(jié)束---->"+processInstance400.isEnded());*/ |
執(zhí)行效果:
------------------------>使流程繼續(xù)向下執(zhí)行 ------------------------>使流程流向200 當(dāng)前流程是否位于200節(jié)點(diǎn)---->true 當(dāng)前流程是否結(jié)束---->false |
上述代碼中使用signalExecutionById()方法時(shí),傳入的是流程實(shí)例的Id,也可以使用以下代碼來(lái)完成同樣的工作:
ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo"); //查詢?cè)摿鞒虒?shí)例的活動(dòng)節(jié)點(diǎn) System.out.println(processInstance.findActiveActivityNames()); //因?yàn)榱鞒虒?shí)例啟動(dòng)后,它會(huì)自動(dòng)向下執(zhí)行,直到遇到state或task等節(jié)點(diǎn)時(shí)暫停下來(lái),在我們的流程定義文件中緊跟在start后的節(jié)點(diǎn)為state,所以流程實(shí)例會(huì)在state節(jié)點(diǎn)暫停下來(lái) Execution execution=processInstance.findActiveExecutionIn("state"); ProcessInstance processInstance200=executionService.signalExecutionById(execution.getId(), "to 200"); System.out.println("當(dāng)前流程是否位于200節(jié)點(diǎn)---->"+processInstance200.isActive("200")); System.out.println("當(dāng)前流程是否結(jié)束---->"+processInstance200.isEnded()); //使流程繼續(xù)向下執(zhí)行(結(jié)束) System.out.println("-------使流程繼續(xù)向下執(zhí)行(結(jié)束)------->"); ProcessInstance instance=executionService.signalExecutionById(processInstance200.getId()); System.out.println("當(dāng)前流程是否結(jié)束---->"+instance.isEnded()); |
執(zhí)行結(jié)果:
[state] 當(dāng)前流程是否位于200節(jié)點(diǎn)---->true 當(dāng)前流程是否結(jié)束---->false -------使流程繼續(xù)向下執(zhí)行(結(jié)束)-------> 當(dāng)前流程是否結(jié)束---->true |
關(guān)于流程實(shí)例幾個(gè)重要的方法:
processInstance.isEnded()判斷程實(shí)例是否結(jié)束結(jié)束返回true,否則返回false
processInstance.isActive(“A”)判斷當(dāng)前流程是否處于A節(jié)點(diǎn)
謹(jǐn)記executionService.signalExecutionById(String executionId, String signalName)方法中executionId為流程實(shí)例Id,signalName為流程向下執(zhí)行的transition的name屬性的值,而不是下一個(gè)節(jié)點(diǎn)的名稱。