单元测试用例如下(只截取了一个片段):
public void testSubProcessResultReject() { ProcessInstance processInstance = executionService .startProcessInstanceByKey("SubProcessDocument");
assertNotNull(processInstance.findActiveExecutionIn("review"));
List<Task> taskList = taskService.findPersonalTasks("johndoe"); Task task = taskList.get(0);
// the task in the sub process instance is completed taskService.completeTask(task.getId(), "reject");
// we check that the process instance has moved to close processInstance = executionService.findProcessInstanceById(processInstance.getId()); assertNotNull(processInstance.findActiveExecutionIn("close")); } |
子流程sub-process标签节点对应的处理类为SubProcessActivity类,我们重点关注SubProcessActivity类中execute方法的实现代码。代码展示如下所示:
重点查看标示红线处的代码,可以看到JBPM在代码中首先创建了一个ExecuteImpl类型的对象作为子流程执行的上下文,之后根据这个子流程的上下文来启动子流程的运转流程,在保存了子流程的上下文后设置主流程的流程状态为WAIT状态。
我们看看红线标示处1的代码,看看JBPM是如何定义和创建子流程的上下文对象的,代码如下:
![](http://dl.iteye.com/upload/attachment/346139/1296fdea-5644-3d28-ac56-7b3b653758af.jpg)
结合上面的代码,我们可以看到JBPM给createProcessInstance方法中的superProcessExecution参数传递的值为主流程的上下文对象。在创建出子流程上下文对象后,JBPM给主流程和子流程的上下文对象设置了上下级的关系,即子流程上下文对象的上级是主流程上下文对象,主流程上下文对象的下级是子流程上下文对象。
子流程在使用start方法启动后,子流程就可以按照正常流程往下运转了。那么当子流程结束时,流程是如何返回到主流程的呢?答案是:当子流程执行到end节点时,JBPM通过执行子流程上下文ExecutionImpl类的对象中的end方法,将流程运行转交到主流程上后再删除子流程的相关数据。
首先我们来看ExecutionImpl类的end方法,代码如下:
需要清楚的是,我们现在拿到的流程上下文对象为子流程上下的对象,superProcessExecution变量的值存放的是主流程上下文对象。可以看到在子流程结束时JBPM执行了红线标示处的代码,即主流程上下文对象调用了signal方法。
此时主流程上下文对象中存放的activity活动对象为子流程节点所对应的活动对象,而子流程上下文对象中存放的是子流程end节点所对应的活动对象。所以在接下来的处理过程中,Signal类中activity活动对象的值为主流程保存的活动对象(也即子流程节点所对应的活动对象),externalActivityBehaviour变量存放的对象是子流程活动的具体处理类对象。故主流程上下文对象调用的signal方法最终会使得子流程活动的具体处理类对象(即SubProcessActivity类的对象)调用signal方法。
如此,我们来查看SubProcessActivity类的signal方法的代码,代码如下所示:
可以看到在此signal方法中,JBPM去掉了主流程和子流程的上下级关系,同时得到了子流程上下文存放的最后一个活动(end节点所对应的活动)的名称(即subProcessActivityName),此名称也即是主流程将要流向的下一个活动的名称。
从上面的代码可以看到在此signal方法中主流程得到了其下一个活动的节点名,之后调用take方法,主流程就可以往下继续运行了。
带有子流程的流程运行的流程可以总结为:启动主流程后,主流程往下运行,在主流程的相关活动节点启动子流程后,子流程往下运行,在子流程运行结束后通过特定的方法(end方法)设置主流程的下一步流向,此时主流程得到控制权,使得主流程可以往下运行。
通过子流程的代码分析,我们可以看到,子流程将控制权交还给主流程是通过调用end方法来完成的。现在来提一个问题,若是我们定义的子流程中没有end节点,主流程能拿到流程下一步流向的控制权吗?我们的单元测试用例可以成功执行吗?感兴趣的同学可以将子流程的xml配置文件中的end节点修改为state节点,再运行单元测试用例看看结果,再好好想一想,结果为什么是这样的。
小提示:一般情况下,一个流程定义是必须具备至少一个流程开始节点和一个流程结束节点的。但是JBPM目前在部署流程定义时是没有校验此规则的。
分发、汇聚功能:
分发和汇聚的配置文件和单元测试用例代码,这里就不再给出了。分发和汇聚对应的处理类分别为ForkActivity和JoinActivity,感兴趣的同学可以看看源代码。这里简单的说说JBPM在此二处的大致设计思路:当遇到fork节点时,JBPM会创建出若干个ExecutionImpl类型的临时上下文对象,并设置这些临时流程上下文对象和流程上下文对象为父子关系,之后调用这些临时上下文对象的take方法,fork节点后的定义的流程就可以向下正常运行。当遇到join节点时,JBPM首先判定是否所有的要求到达的节点均达到了join节点,若不是,则不作处理;若全部节点均达到了join节点,则调用所有这些临时流程上下文对象的end方法,结束掉这些临时流程上下文运行流程,同时删除这些临时流程上下文对应的相关数据。处理完上述步骤后,join节点后的定义的流程就可以往下正常运行了。
我们在Eclipse中查看实现了ActivityBehaviour接口的对象有:
![](http://dl.iteye.com/upload/attachment/346149/511606a1-22d2-3eec-8304-4c94d6c54b40.jpg)
我们就可以把上图中展示的具体类和JBPM的jpdl中提供的xml标签节点一一对应起来,对具体代码一一进行分析,逐步深入了解JBPM的运转机制。
通过上面的代码分析,我们了解了JBPM的流程运转机制,了解了JBPM提供的几个复杂模型。知道了这些基本的知识后,我们可以结合JBPM提供的单元测试,顺藤摸瓜,一一查看分析JBPM的源代码了。