JBPM 7.17 学习笔记(4)流程变量和任务变量

在 HumanTask 示例中,使用了流程变量和任务变量。根据二者作用范围的不同,我们又分别把它们称之为全局变量和局部变量。

流程变量

将 HumanTask.bpmn 导入到 workbench 中用流程设计器查看流程图。

查看流程实例变量。

打开 HumanTaskExample.java,找到以下代码:

// start a new process instance
Map<String, Object> params = new HashMap<String, Object>();
params.put("userId", "krisv");
params.put("description", "Need a new laptop computer");
ksession.startProcess("com.sample.humantask", params);

在流程启动时,在 startProcess 方法的第二个参数中传递一个 Map,这 map 将会用于初始化流程变量的值。也就是说流程实例启动后,流程变量中的 userId 和 description 将被赋值。

此外,还有一个 date 变量也会被赋值,但是不是通过 startProcess() 方法赋值的,而是通过一个脚本任务来赋值的。

选中流程图中的名为 Time 的任务,打开属性面板:

脚本任务是自动执行的,它调用了一段 java 代码,利用 kcontext 的 setVariable 方法将 date 变量设置为当前时间。

为了验证这一点,我们可以在任务执行前打印出流程变量的值。打印流程变量的代码是这段代码:

Map<String, Object> content = taskService.getTaskContent(task4.getId());
for (Map.Entry<?, ?> entry : content.entrySet()) {
	System.out.println(entry.getKey() + " = " + entry.getValue());
}

在 HumanTaskExample.java 中找到这段代码,选中它,右键 Refactor -> Extract -> Method …,将它抽取成一个私有方法:

private static void getVariables(TaskService taskService, TaskSummary task4) {
        Map<String, Object> content = taskService.getTaskContent(task4.getId());
        for (Map.Entry<?, ?> entry : content.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
}

jBMP 7 似乎不允许直接读取流程变量,尝试了各种直接访问流程变量的方法都不成功。

实际上这个方法打印的并不会打印流程变量,而只会打印任务变量,即 Assignments 中的输入变量。因为这些变量已经和全局变量进行了绑定,所以也可以用这种方式查看全局变量。

然后在,每次 taskService.start() 语句后调用这个方法,比如 getVariables(taskService,task1);,注意改变 task1 为不同的变量。

在每个 getVariables() 调用之后添加断点。Debug 运行。

当第一个断点停下时,控制台中会打印出:

date = Fri Mar 08 13:39:17 CST 2019
TaskName = Request Review
NodeName = Review
description = Need a new laptop computer
SwimlaneActorId = null
userId = krisv
GroupId = sales

这是第一个用户任务,当第一个用户任务开始时,脚本任务已经执行,所以这里的 date 变量是有值的,TaskName 是当前任务(流程图中的 Review 节点)的任务名称,NodeName 是当前任务的节点名称,这两者可以一样,也可以不一样。

description 和 userId 的值就是 startProcess 方法赋值的,值和代码中设置的是一样的。

GroupId 是任务的 Groups 属性所设置的。

继续执行,断点在第二个任务(即 User Approval 节点)start 后停下,此时控制台打印:

result = Accept
date = Fri Mar 08 13:39:17 CST 2019
TaskName = Request Approval
NodeName = User Approval
description = Need a new laptop computer
comment = Agreed, existing laptop needs replacing
ActorId = krisv
userId = krisv

和之前相比,增加了 result 和 comment 变量。在上一个任务完成时:

Map<String, Object> results = new HashMap<String, Object>();
results.put("comment", "Agreed, existing laptop needs replacing");
results.put("outcome", "Accept");
taskService.complete(task1.getId(), "sales-rep", results);

jBPM 7 似乎不允许直接设置全局变量,尝试了各种方法都不成功,complete 方法似乎是唯一的设置全局变量的方法。

TaskService 的 complete 方法设置全局变量其实比较绕。首先要通过一个 Map 来设置任务的输出变量,然后引擎将它同步到全局变量。然后在下一个任务中,又要通过读取输入变量,才能读取到全局变量的值。

例如在第一个任务 complete 时,我们在 map 中设置了 comment 和 outcome。这两个其实是任务的输入变量。然后运行时引擎会根据 Assignments 的设置将它们同步给全局变量 comment 和 result。

其中 outcome 变量会绑定到全局变量 result。你可以查看任务的分配属性(Assignments):

outcome 绑定了全局变量 result。所以 taskService.complete 方法实际上是对局部任务变量进行赋值,然后由运行时引擎同步给全局变量。

而在第二个任务中,当我们用 getVariables 打印第二个任务的局部变量时,局部变量中就包括了 result:

这个 result 绑定的是全局变量 result。所以上面的打印结果中包含了 result。

最后一个是 ActorId 变量。这来自于任务的 Actors 属性:

#{userId}引用了变量 userId。

继续执行,断点在第三个任务(Manager Approval 节点)执行时停下。控制台:

result = Accept
date = Fri Mar 08 13:39:17 CST 2019
TaskName = Request Approval
NodeName = Manager Approval
description = Need a new laptop computer
comment = Agreed, existing laptop needs replacing
userId = krisv
GroupId = PM

除了 GroupId 变量(来自任务的 Groups 属性)外,没有增加新的变量。但是在 User Approval 节点的办结代码中,修改了 outcome 变量:

results = new HashMap<String, Object>();
results.put("outcome", "Agree");
taskService.complete(task2.getId(), "krisv", results);

但是,这个 outcome 变量绑定的不再是 result 全局变量,而是 resultUser 全局变量:

但在 Manager Approval 任务的打印中,我们并没有看到 resultUser 变量!
这是因为 User Approval 和 Manager Approval 使用的并行网关!二者不是前后关系,而是并行关系。也就是说,User Approval 节点的下一节点并不是 Manager Approval,而是 Notification 节点。而 TaskService.complete 方法传递变量的方式是向下一节点传递,因此在 Manager Approval 节点不会收到 User Approval 节点传递的变量。如果想看到 User Approval 的传递的局部变量,应该在 Notification 节点进行打印。

继续执行,断点在第四个节点(Notification节点)停下。控制台:

result = Accept
date = Fri Mar 08 13:39:17 CST 2019
resultUser = Agree
resultManager = Agree
TaskName = Request Notification
NodeName = Notification
description = Need a new laptop computer
comment = Agreed, existing laptop needs replacing
SwimlaneActorId = sales-rep
userId = krisv
GroupId = sales

看到了吧!在 Notification 节点,你不仅看到了 User Approval 新增的 resultUser 变量,还看到了 Manager Approval 增加的 resultManager 变量!因为 Manager Approval 的下一节点还是 Notification(再次使用了一个并行网关)。

再看一眼打印全局变量的方法,它需要一个 TaskService 实例,和一个 TaskSummary 对象(其实只需要 taskId 就行了)。那么假设这个任务已经 complete,甚至整个运行时已经被销毁了,它还能工作吗?还是报空指针异常?

让我们来试一试,在任务 complete 和 disposeRuntimeEngine 之后增加一个 getVariables 语句:

taskService.complete(task4.getId(), "sales-rep", null);

getVariables(taskService,task4);
System.out.println("Process instance completed");
    		
manager.disposeRuntimeEngine(runtime);
getVariables(taskService,task4);

变量仍然打印出来了,没有任何问题。

2017年jBPM 正式发布了全新的 7版本。jBPM 是一个完全开源的业务流程管理(BPM)和案例管理解决方案。它支持流程和案例的完整生命周期,从编写工具到执行一直到监控和管理。 在核心引擎之上,提供了许多功能和工具来支持整个生命周期中的业务流程: 基于Eclipse和基于Web的编辑器,用于支持业务流程的图形化创建(拖放)。 基于JPA / JTA的可插拔持久性和事务。 基于WS-HumanTask的可插拔人工任务服务,用于包含需要由人类执行者执行的任务。 管理控制台支持流程实例管理,任务列表和任务表单管理以及报告。 部署流程的可选流程仓库(和其他相关知识)。 历史记录(用于查询/监视/分析)。 与Seam,Spring,OSGi等集成 BPM通过以业务用户和开发人员喜欢的方式提供流程管理功能和工具,从而实现业务分析师,开发人员和最终用户之间的桥梁。域特定的节点可以插入调色板,使业务用户更容易理解这些过程。 jBPM支持自适应和动态过程,需要灵活性来模拟复杂的现实生活中的情况,这些情况不能用刚性过程轻松描述。我们通过允许他们控制进程的哪些部分来执行,动态地偏离进程等,使控制回到终端用户。 jBPM也不仅仅是一个独立的流程引擎。复杂的业务逻辑可以被建模为业务流程与业务规则和复杂事件处理的组合。jBPM可以与Drools项目相结合,以支持将这些范例集成到一起的统一环境,您可以将业务逻辑作为过程,规则和事件的组合进行建模。 工作是MAVEN+eclipse jBPM jars也可以在中央maven仓库中使用 (也可以在JBoss maven仓库中)。 如果您使用Maven,只需添加一个依赖关系pom.xml: org.jbpm jbpm-test 7.3.0.Final 这与Gradle,Ivy和Buildr类似。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值