jbpm学习笔记(六) jbpm的核心 jpdl流程定义语言详解(一)
jpdl是jbpm的最核心,涉及到各方面的内容,所以我打算用多篇博文记录它
一, Jpdl语言是以xml为表现形式的,根元素是process,我们看看process元素的一些属性
<?xml version="1.0" encoding="UTF-8"?><process name="angel" xmlns="http://jbpm.org/4.4/jpdl"><!-- 流程开始后转移到wait for response state --><start><transition to="wait for response" /></start> <!-- 这里有两个transition供选择,二者选其一 --><state name="wait for response"><transition name="accept" to="submit document" /><transition name="reject" to="try again" /></state><!-- 此活动被上面名为accept 的transition指向 --><state name="submit document" /><!-- 此活动被上面名为reject 的transition指向 --><state name="try again" /></process>
下面我们编写代码使此流程运行起来,首先根据此流程定义发起实例:
ProcessInstance processInstance=executionService.startProcessInstanceByKey(“StateChoice”);
假如现在流程到达了 wait for response state活动,则实例会一直等待外部触发的出现。此state活动拥有两个流出转移,外部触发调用通过提供不同的流出转移信号名称(signal name) 来实现选择流转,下面使用accept作为信号名称:
//获取流程执行的ID String executionId=processInstance.findActiveExecutionIn(“wait for response”).getId(); //触发accept型号 processInstance=executionService.signalExecutionById (executionId,”accept”); assertTrue(processInstance.isActive(“submit document”));
3,decision
根据条件在多个流转路径中选择其一通过,也就是做一个决定性的判断,这时候使用
decision活动是个正确的选择。
Decision活动可以拥有多个流出转移,当流程实例到达decision活动时,会根据最先匹配成功的一个条件 自动地通过相应的流出转移。
(1),使用decision活动的condition
使用decision活动的condition元素
Decision活动中会运行并判断其每一个transition元素里的流转条件----流转条件由condition元素表示。当遇到一个transition的condition值为true或者一个没有设置condition的transition,那么流程就立刻流向这个transtion。
相关jpdl如下:
<?xml version="1.0" encoding="UTF-8"?><process name="decisionConditions" xmlns="http://jbpm.org/4.4/jpdl"><start><transition to="decisionGo" /></start> <!-- "#{content}" 即为判断表达式。在这里会返回变量content的字符串值 --> <decision name="decisionGo"> <!-- content 值为good时的转移 --> <transition to="submit" > <condition expr="#{content=='good'}"/> </transition> <!-- content 值为bad时的转移 --> <transition to="try again" > <condition expr="#{content=='bad'}"/> </transition> <!-- content 值为ugly时的转移 --> <transition to="give up" > <condition expr="#{content=='ugly'}"/> </transition> </decision> <state name="submit" /> <state name="try again" /> <state name="give up" /> </process>
在单元测试中,设置流程变量content的值为good:
Map<String,Object> vals=new HashMap<String, Object> ();vals.put("content","good");//发起流程实例ProcessInstance processInstance=executionService.startProcessInstanceByKey("decisionConditions",vals);//那么,可以断言流程实例流向了submit活动assertTrue(processInstance.isActive("submit"));
(2),使用decision活动的expr属性
你可以利用decision活动本身具有的expr(表达式)属性来判断流程的转向,decision活动的expr属性值可直接返回字符串类型的流出转移名称,指定需要流转的路径。
相关jpdl代码如下
<?xml version="1.0" encoding="UTF-8"?><process name="decisionExpr" xmlns="http://jbpm.org/4.4/jpdl"><start><transition to="decisionGo" /></start> <!-- "#{content}" 即为判断表达式。在这里会返回变量content的字符串值 --> <decision expr="#{content}" name="decisionGo"> <!-- content 值为good时的转移 --> <transition name="good" to="submit" /> <!-- content 值为bad时的转移 --> <transition name="bad" to="try again" /> <!-- content 值为ugly时的转移 --> <transition name="ugly" to="give up" /> </decision> <state name="submit" /> <state name="try again" /> <state name="give up" /> </process>
在单元测试中,设置流程变量content的值为good:
Map<String,Object> vals=new HashMap<String, Object>();vals.put("content","good");//发起流程实例ProcessInstance processInstance=executionService.startProcessInstanceByKey("decisionExpr",vals); /那么,可以断言流程实例流向了submit活动assertTrue(processInstance.isActive("submit"));
(3),使用decision活动的handler元素
也许以上两种判断流转的方式对你来说还不够灵活,也许你需要在判断流转时计算大量,复杂的业务逻辑,那么,自己实现判断处理接口,即通过decision handler的方式,将给你无限自由的空间。
首先,必须实现DecisionHandler接口,将流转判断的决定权委派给这个实现类,这个接口的定义如下:
Public interface DecisionHandler{
//这个接口就只有一个方法,提供流程实例的执行上下文(execution)作为参数,需要返回字符串型的转移名称
String decide(OpenExecution execution);
}
这个handler需要作为decision活动的子元素被配置。
相关的jpdl如下:
<?xml version="1.0" encoding="UTF-8"?><process name="decisionTest" xmlns="http://jbpm.org/4.4/jpdl"><start><transition to="decisionGoHandler" /></start> <decision name="decisionGoHandler"> <!-- 所有的流转判断逻辑都被委派给了这个ContentEvaluation handler 统一处理 --> <handler /> <transition name="good" to="submit"/> <transition name="bad" to="try again"/> <transition name="ugly" to="give up"/> </decision> <state name="submit" /> <state name="try again" /> <state name="give up" /> </process>ContentEvaluation这个类的代码如下:
package org.test;import org.jbpm.api.jpdl.DecisionHandler;import org.jbpm.api.model.OpenExecution;public class ContentEvaluation implements DecisionHandler {@Overridepublic String decide(OpenExecution execution) {String content = (String) execution.getVariable("content");if (content.equals("you are good")) {return "good";}if (content.equals("you are bad")) {return "bad";} return "ugly";}}运行流程实例的单元测试代码如下:
Map<String,Object> vals=new HashMap<String, Object>();//设置流程变量content的值为 you are goodvals.put("content","you are good");//发起流程实例,并设置流程变量ProcessInstance pi=executionService.startProcessInstanceByKey("decisionHandler",vals);//断言流向了预期的活动assertTrue(pi.isActive("submit"));
现在有一个问题出现了,发觉了吗,decision活动和state活动都能实现条件流转,是的,但是这两种方式有何区别,在实际业务应用中该选择何种方式呢?
区别如下:
如果decision活动定义的流转条件没有任何一个得到满足,那么流程实例将无法进行下去,会抛出异常。
如果state活动有多个流出转移,且同样没有任何一个得到满足,那么流程实例将流向state活动定义的第一条流出转移,从而进行下去。
也就是说:decision活动具有更加严格的条件判断特性。
下篇讲解fork-join(分支/聚合活动)和end