作者:
JeffreyHsu
盡管jbpm非常強大,是目前最適合商業化的開源工作流引擎,可以開發出復雜的流程,但是特別遺憾的是并不支持并發子流程(multiple-subprocess)
有一次我需要做一個復雜的流程,主流程里要求同時啟動多個并發執行的子流程,并且子流程的數目和啟動的時間都不確定,當所有子流程都結束以后,主流程才繼續執行。我們知道jbpm里有子流程的設定,有專門的節點ProcessState來處理,但是后來發現無論如何也實現不了多子流程并發執行,后來看其源碼知道因為subprocess是作為ProcessState的一個屬性,也就是說ProcessState只能包含一個subprocess的定義,并且最重要的是processInstance.getRootToken()和子流程相關的只有createSubProcessInstance, getSubProcessInstance, setSubProcessInstance三個方法,這意味著主流程的rootToken只能設置一個子流程,jbpm并不直接支持多子流程。
那么我們就必須用一個變通的方法來實現,“并發”很自然的讓我們想到了fork,但是這里的fork不能搭配join來使用,具體原因,將在后面討論。
下面先給出流程圖:

state節點用來啟動子流程(實際應用可以換成Task-Node),state進入fork后同時進入兩個分支,一條去啟動子流程,另一條回到自己,這樣表面看來state沒有動,而同時你又可以啟動第2個,第3個……子流程,需要注意的是第2條子流程和第1個子流程并不處于同一級上,而比第一個子流程低一級,具體請看后面一張圖就明白了,分解后的:

從圖中我們可以看到后一個子流程的整棵樹是前一個子流程的兄弟,但是在業務級上是并發的效果,已經實現我們前面的需求。
現在來說說為什么不能用join而直接用end,因為會產生一個問題,state3和sub process 2都到達了join以后,state2下面的fork就結束了,就會立刻越過join到達end,而sub process 1即使執行完畢到達了join卻仍然在傻傻等待著他的兄弟分支也到達join(而實際上它已經自跑到end去了)一同結束,這樣sub process 1就會永遠停在join動彈不得,業務無法進行。
這是我的一個解決方案,但還有一個問題,雖然全部的子流程都能結束,主流程也能結束,但因為沒有join,主流程的rootToken仍然停留在fork節點上。目前我尚不知如何解決,希望各位大家能提出其他更好的解決辦法。
初學jbpm,水平有限,有不當之處還請高手斧正
最后附上demo代碼供參考:
代碼
-
- import static org.junit.Assert.*;
-
- import org.jbpm.graph.def.ProcessDefinition;
- import org.jbpm.graph.exe.ProcessInstance;
- import org.jbpm.graph.exe.Token;
- import org.jbpm.graph.node.ProcessState;
- import org.junit.Before;
- import org.junit.Test;
-
- public class MultiProcessTest {
- private ProcessDefinition superProcessDefinition;
-
- private ProcessDefinition subProcessDefinition;
-
- @Before
- public void setUp() throws Exception {
- superProcessDefinition = ProcessDefinition.parseXmlString(
- "<process-definition name='super'>" +
- " <start-state name='start'>" +
- " <transition to='state' />" +
- " start-state>" +
- " <state name='state'>" +
- " <transition name='create sub' to='fork' />" +
- " <transition name='end' to='end' />" +
- " state>" +
- " <fork name='fork'>" +
- " <transition name='back' to='state' />" +
- " <transition name='go to sub' to='sub process' />" +
- " fork>" +
- " <process-state name='sub process'>" +
- " <sub-process name='sub' />" +
- " <transition to='end' />" +
- " process-state>" +
- " <end-state name='end' />" +
- "process-definition>");
-
- subProcessDefinition = ProcessDefinition.parseXmlString(
- "<process-definition name='sub'>" +
- " <start-state name='start'>" +
- " <transition to='wait' />" +
- " start-state>" +
- " <state name='wait'>" +
- " <transition to='end' />" +
- " state>" +
- " <end-state name='end' />" +
- "process-definition>");
- ProcessState processState = (ProcessState) superProcessDefinition
- .getNode("sub process");
- processState.setSubProcessDefinition(subProcessDefinition);
- }
-
- @Test
- public void testMultiProcesses() {
- ProcessInstance pi = new ProcessInstance(superProcessDefinition);
-
- // 啟動一個主流程
- pi.signal();
- assertEquals("state", pi.getRootToken().getNode().getName());
-
- // 進入分支,此處將進入子流程
- pi.signal("create sub");
- // 主流程token將停留在fork節點上
- assertEquals("fork", pi.getRootToken().getNode().getName());
-
- // fork分為兩支,其中一支的節點停留在ProcessState上
- Token subProcessToken1 = pi.getRootToken().getChild("go to sub");
- ProcessInstance subPi1 = subProcessToken1.getSubProcessInstance();
- assertEquals("wait", subPi1.getRootToken().getNode().getName());
-
- // 另一支返回了state節點,實際上并沒有返回,這個state節點不同于先前的state,它們并不在同一個path中
- Token stateToken1 = pi.getRootToken().getChild("back");
- assertEquals("state", stateToken1.getNode().getName());
-
- // 再次進入fork,啟動第二個子流程
- stateToken1.signal("create sub");
- ProcessInstance subPi2 = stateToken1.getChild("go to sub")
- .getSubProcessInstance();
- // 雖然都是子流程,但它們并不相同,在邏輯上是屬于并發的無關系的子流程
- assertFalse(subPi1.equals(subPi2));
- // 結束第二個子流程
- subPi2.signal();
- assertTrue(subPi2.hasEnded());
- assertFalse(pi.hasEnded());
-
- // 結束第一個子流程,但主流程仍未結束
- subPi1.signal();
- assertTrue(subPi1.hasEnded());
- assertFalse(pi.hasEnded());
-
- // 結束第二個子流程中的state,第一子流程的back分支結束,從而主流程也結束
- Token stateToken2 = stateToken1.getChild("back");
- assertEquals("state", stateToken2.getNode().getName());
- assertFalse(stateToken1.hasEnded());
- assertFalse(pi.hasEnded());
- stateToken2.signal("end");
-
- assertTrue(stateToken1.hasEnded());
- assertTrue(subPi1.hasEnded());
- assertTrue(pi.getRootToken().getChild("back").hasEnded());
- assertTrue(pi.getRootToken().getChild("go to sub").hasEnded());
- // 主流程結束了
- assertTrue(pi.hasEnded());
- // 雖然主流程已經結束了,但是因為子流程沒有join,所以其rootToken仍然停留在fork上
- assertEquals("fork", pi.getRootToken().getNode().getName());
- // 第二個子流程到達的end和主流程中的end并不是同一個節點
- assertTrue(!pi.getRootToken().getNode().equals(stateToken2.getNode()));
- }
- }
posted on 2007-09-11 17:48
jbpm 閱讀(1023)
評論(0) 編輯 收藏 所屬分類:
jbpm深入研究