流程变量 Variables

在 Activiti 中,流程变量(Process Variables)是流程实例或任务级别的数据,可以在流程的不同阶段设置和访问。以下是几种设置流程变量的方式及其区别、优先级和覆盖规则:


1. 设置流程变量的方式

1.1 启动流程时设置流程变量

使用 runtimeService.startProcessInstanceByKeyruntimeService.startProcessInstanceById 启动流程时,可以传入流程变量。

Map<String, Object> variables = new HashMap<>();
variables.put("key1", "value1");
variables.put("key2", 100);

runtimeService.startProcessInstanceByKey("myProcess", businessKey, variables);
  • 作用范围:这些变量属于流程实例级别,可以在整个流程实例中访问。
  • 优先级:启动时设置的变量是初始变量,优先级最低(可以被后续设置的变量覆盖)。

1.2 办理任务时设置流程变量

使用 taskService.complete(taskId, variables) 完成任务时,可以传入流程变量。

Map<String, Object> variables = new HashMap<>();
variables.put("key2", 200);
variables.put("key3", true);

taskService.complete(taskId, variables);
  • 作用范围:这些变量属于流程实例级别,可以在整个流程实例中访问。
  • 优先级:完成任务时设置的变量会覆盖之前同名的流程变量。

1.3 使用 taskService.setVariable 设置任务变量

使用 taskService.setVariable 可以在任务执行过程中设置流程变量。

taskService.setVariable(taskId, "key4", "value4");
  • 作用范围:这些变量属于流程实例级别,可以在整个流程实例中访问。
  • 优先级:与完成任务时设置的变量相同,会覆盖之前同名的流程变量。

1.4 使用 taskService.setVariableLocal 设置任务本地变量

使用 taskService.setVariableLocal 可以设置任务本地变量。

taskService.setVariableLocal(taskId, "key5", "value5");
  • 作用范围:这些变量属于任务级别,只能在当前任务中访问。
  • 优先级:任务本地变量不会覆盖流程实例级别的变量,两者是独立的。

2. 变量优先级和覆盖规则

2.1 流程实例变量 vs 任务本地变量

  • 流程实例变量:在整个流程实例中共享,优先级较低(可以被后续设置的流程实例变量覆盖)。
  • 任务本地变量:仅在当前任务中有效,优先级较高(不会覆盖流程实例变量,也不会被流程实例变量覆盖)。

2.2 变量覆盖规则

  • 如果使用 taskService.complete(taskId, variables)taskService.setVariable 设置变量,会覆盖同名的流程实例变量。
  • 如果使用 taskService.setVariableLocal 设置变量,不会影响流程实例变量,任务本地变量仅在当前任务中有效。

2.3 变量查询规则

  • 使用 runtimeService.getVariable 查询变量时,只能查询流程实例变量。
  • 使用 taskService.getVariable 查询变量时,会先查询任务本地变量,如果不存在,则查询流程实例变量。
  • 使用 taskService.getVariableLocal 查询变量时,只能查询任务本地变量。

3. 示例代码

以下是一个完整的示例,展示不同方式设置变量的行为:

// 启动流程时设置变量
Map<String, Object> startVariables = new HashMap<>();
startVariables.put("key1", "value1");
startVariables.put("key2", 100);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess", businessKey, startVariables);

// 查询流程实例变量
String value1 = (String) runtimeService.getVariable(processInstance.getId(), "key1"); // "value1"
Integer value2 = (Integer) runtimeService.getVariable(processInstance.getId(), "key2"); // 100

// 办理任务时设置变量
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
Map<String, Object> completeVariables = new HashMap<>();
completeVariables.put("key2", 200);
completeVariables.put("key3", true);
taskService.complete(task.getId(), completeVariables);

// 查询更新后的流程实例变量
value2 = (Integer) runtimeService.getVariable(processInstance.getId(), "key2"); // 200
Boolean value3 = (Boolean) runtimeService.getVariable(processInstance.getId(), "key3"); // true

// 使用 setVariable 设置变量
Task newTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
taskService.setVariable(newTask.getId(), "key4", "value4");

// 查询更新后的流程实例变量
String value4 = (String) runtimeService.getVariable(processInstance.getId(), "key4"); // "value4"

// 使用 setVariableLocal 设置任务本地变量
taskService.setVariableLocal(newTask.getId(), "key5", "value5");

// 查询任务本地变量
String value5 = (String) taskService.getVariableLocal(newTask.getId(), "key5"); // "value5"
String value5Global = (String) runtimeService.getVariable(processInstance.getId(), "key5"); // null

4. 总结

设置方式作用范围优先级覆盖规则
runtimeService.startProcessInstanceByKey流程实例级别可以被后续设置的流程实例变量覆盖
taskService.complete(taskId, variables)流程实例级别覆盖同名的流程实例变量
taskService.setVariable流程实例级别覆盖同名的流程实例变量
taskService.setVariableLocal任务级别独立不影响流程实例变量
  • 流程实例变量:在整个流程中共享,优先级较低。
  • 任务本地变量:仅在当前任务中有效,优先级较高,且独立于流程实例变量。
  • 覆盖规则:后设置的变量会覆盖同名的流程实例变量,任务本地变量不会覆盖流程实例变量。

在 Activiti 中,taskService.complete(taskId, variables)taskService.setVariable(taskId, "flag", 0) 都是设置流程变量的方式,但它们的行为和优先级有所不同。以下是对它们的详细解释:


1. taskService.complete(taskId, variables)

  • 作用:完成任务并设置流程变量。
  • 行为
    • 完成任务后,流程会继续执行到下一个节点。
    • 传入的变量会作为流程实例变量保存。
  • 优先级
    • 这些变量会在任务完成时设置,覆盖之前同名的流程实例变量。
    • 如果任务完成后流程进入下一个节点,这些变量会立即生效。

2. taskService.setVariable(taskId, "flag", 0)

  • 作用:在当前任务执行过程中设置流程变量。
  • 行为
    • 设置的变量会立即生效,但不会触发任务完成或流程流转。
    • 这些变量会覆盖之前同名的流程实例变量。
  • 优先级
    • 设置的变量会立即覆盖同名的流程实例变量。

3. 优先级和覆盖规则

  • 优先级
    • taskService.setVariable(taskId, "flag", 0) 的优先级高于 taskService.complete(taskId, variables)
    • 这是因为 setVariable 是立即生效的,而 complete 是在任务完成时才生效。
  • 覆盖规则
    • 如果在调用 taskService.complete(taskId, variables) 之前调用了 taskService.setVariable(taskId, "flag", 0),那么 setVariable 设置的变量会立即覆盖同名的流程实例变量。
    • 如果在 complete 中传入了同名的变量,那么 complete 中的变量会覆盖 setVariable 设置的变量。

4. 示例代码

以下是一个示例,展示两者的优先级和覆盖行为:

// 启动流程
Map<String, Object> startVariables = new HashMap<>();
startVariables.put("flag", 1);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess", startVariables);

// 查询任务
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

// 使用 setVariable 设置变量
taskService.setVariable(task.getId(), "flag", 0);

// 查询变量
Integer flagValue = (Integer) runtimeService.getVariable(processInstance.getId(), "flag");
System.out.println("After setVariable, flag = " + flagValue); // 输出: 0

// 使用 complete 完成任务并设置变量
Map<String, Object> completeVariables = new HashMap<>();
completeVariables.put("flag", 2);
taskService.complete(task.getId(), completeVariables);

// 查询变量
flagValue = (Integer) runtimeService.getVariable(processInstance.getId(), "flag");
System.out.println("After complete, flag = " + flagValue); // 输出: 2

5. 总结

操作行为优先级覆盖规则
taskService.setVariable(taskId, "flag", 0)立即设置流程变量,覆盖同名变量。立即覆盖同名变量。
taskService.complete(taskId, variables)完成任务并设置流程变量,变量在任务完成时生效。覆盖 setVariable 设置的变量。
  • 优先级setVariable 的优先级高于 complete
  • 覆盖规则
    • setVariable 会立即覆盖同名变量。
    • complete 会在任务完成时覆盖 setVariable 设置的变量。

因此,如果你在任务完成前调用了 setVariable,那么 setVariable 的值会立即生效;如果在 complete 中传入了同名变量,那么 complete 的值会覆盖 setVariable 的值。