您的位置:首页 > 产品设计 > 产品经理

说说 jBPM 流程定义语言(5)—— fork - join (分支、聚合活动)

2018-02-07 10:52 711 查看
当我们需要流程并发(concurrency)执行时,就需要使用到 fork-join 活动组合,fork活动可以使流程在一条主干上出现并行的分支,join 活动则可以使流程的并行分支聚合成一条主干。

Fork 活动具有1个 name 属性和 n 个流出转移元素。

join 活动的独特属性:

属性类型默认值是否必需描述
multiplicityinteger流入转移数可选流程执行中,当指定的流入转移数量(multiplicity)到达 join 活动后,流程即会聚合,沿着 join 活动的唯一流出转移继续执行流转。其他未到达的流入转移则会忽略,从而实现按流入转移数量聚合的场景,因此,multiplicity 属性不应该大于 join 活动定义流入转移数量。
lockmode字符串枚举:none、read、upgrade、upgrade_nowait、wirteupgrade可选指定 hibernate 的数据锁模式。因为 join 活动支持并发自动活动事务,因此需要在 join 活动上防止两个还没有聚合的同步事务活动互相锁定对象的事务资源,从而导致死锁。


流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>

<process key="ConcurrencyGraphBased" name="ConcurrencyGraphBased" xmlns="http://jbpm.org/4.4/jpdl">
<start g="23,212,174,52" name="start1">
<transition to="fork1"/>
</start>
<state g="170,134,174,52" name="开发票">
<transition g="653,158:" to="join2"/>
</state>
<state g="173,208,174,52" name="装车">
<transition g="404,230:" to="join1"/>
</state>
<state g="174,272,174,52" name="打印订购单">
<transition g="402,303:" to="join1"/>
</state>
<!-- 3 个并行的分支-->
<fork g="103,211,174,52" name="fork1">
<transition g="126,164:" to="开发票"/>
<transition to="装车"/>
<transition g="128,298:" to="打印订购单"/>
</fork>
<!-- 聚合 “装车” 与 “打印订购单” 的分支活动-->
<join g="375,242,174,52" name="join1">
<transition to="发车到目的地"/>
</join>
<state g="445,241,174,52" name="发车到目的地">
<transition g="651,266:" to="join2"/>
</state>
<!-- 聚合所有活动-->
<join g="629,187,174,52" name="join2">
<transition to="end1"/>
</join>
<end g="704,189,174,52" name="end1"/>
</process>


测试代码:

//发起实例
ProcessInstance processInstance = executionService.startProcessInstanceByKey
("ConcurrencyGraphBased");

String pid = processInstance.getId();

//构造活动名称集合用于验证分支
Set<String> expectedActivityNames = new HashSet<String>();
expectedActivityNames.add("开发票");
expectedActivityNames.add("装车");
expectedActivityNames.add("打印订购单");

//断言当前活动,即为产生的三个分支
assertEquals(expectedActivityNames, processInstance.findActiveActivityNames());

//发出执行信号,通过 "开发票" 活动,流程会在最后的聚合活动 “final join” 上等待其他分支的到来
String sendInvoiceExecutionId = processInstance.findActiveExecutionIn("开发票").getId();
processInstance = executionService.signalExecutionById(sendInvoiceExecutionId);
expectedActivityNames.remove("开发票");

//断言还有两个分支在等待
assertNotNull(processInstance.findActiveExecutionIn("装车"));
assertNotNull(processInstance.findActiveExecutionIn("打印订购单"));

//发出执行信号,通过 装车 分支活动
String loadTruckExecutionId = processInstance.findActiveExecutionIn("装车")
.getId();
processInstance = executionService.signalExecutionById(loadTruckExecutionId);
expectedActivityNames.remove("装车");

//发出执行信号,通过 打印订购单 分支活动
String printShippingDocumentsId = processInstance.findActiveExecutionIn("打印订购单")
.getId();
processInstance = executionService.signalExecutionById(printShippingDocumentsId);
expectedActivityNames.remove("打印订购单");

//断言通过了第一个聚合活动 join1, 到达了 “发车到目的地” 活动
expectedActivityNames.add("发车到目的地");
assertEquals(expectedActivityNames, processInstance.findActiveActivityNames());
assertNotNull(processInstance.findActiveExecutionIn("发车到目的地"));

//发出执行信号,通过 "发车到目的地" 分支活动
String driveTruckExecutionId = processInstance.findActiveExecutionIn("发车到目的地").getId();
processInstance = executionService.signalExecutionById(driveTruckExecutionId);

//最终的聚合活动,等它最后一个流入转移后,就会流向 end 活动,至此所有流程实例结束。
assertNull("execution " + pid + " should not exist", executionService
.findExecutionById(pid));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: