一、RuntimeService介绍
RuntimeService
- 启动流程及对流程数据的控制。
- 流程实例【ProcessInstance】和执行流【Execution】查询。
- 触发流程操作、接受消息和信号。
RuntimeService启动流程及变量管理
- 启动流程的常用方式(id,key,message)
- 启动流程可选参数(businessKey,variables,tenantId)
- 变量(variables)的设置和获取
流程实例与执行流
- 流程实例(ProcessInstance)表示一次工作流业务的数据实体。
- 执行流(Execution)表示流程实例中具体的执行路径。
- 流程实例接口继承于执行流
流程触发
- 使用trigger触发ReceiveTask节点
- 触发信号捕获事件signalEventReceived【全局触发信号】
- 触发消息捕获事件messageEventReceived【针对流程触发消息】
相关方法
相关详解
流程实例与执行流概念
- 在Activiti中,启动了一个流程,会创建一个流程实例(Processlnstance),每个流程实例至少会有一个执行流(Execution) 。当流程实例没有流程分支时,一般情况下只会存在一个执行流;假设流程出现两个分支,此时Activiti将会有三个执行流,第一个为原来流程的主执行流,而其余两个为子执行流。
流程实例和执行流对象
- Processlnstance是一个接口,一个Processlnstance实例表示一个流程实例,Processlnstance实际上是执行流(Execution)的子接口,流程实例也是一个执行流。Processlnstance中有Execution没有的属性,例如流程定义和业务主键。当得到的是一个Processlnstance实例时,就将其看作一个流程实例;当得到一个Execution实例时,它就是一个执行流。流程实例与执行流的数据保存在执行表ACT_RU_EXECUTION中,对应的映射实体为ExecutionEntitylmpl。
启动流程
startProcesslnstanceByld方法
- startProcesslnstanceByld(String processDefinitionld): 根据流程定义ID启动流程,在进行流程部署时,可以得到一个 Deployment的实例,根据Deployment实例的ID可以查询到ProcessDefinition的实例。
- startProcesslnstanceByld(String processDefinitionld, Map<String,Object> variables):该方法可以为流程设置参数,第二个参数为Map。
- startProcesslnstanceByld(String processDefinitionld, String businessKey):使用流程定义ID和业务主键启动流程,业务主键会被保存到执行表的BUSINESS_KEY字段。
- startProcesslnstanceByld(String processDefinitionld, String businessKey, Map<String, Object> variables):该方法既可以设置业务主键,也允许传入流程参数。
startProcesslnstanceByKey方法
- startProcesslnstanceByKey(String processDefinitionKey):根据流程文件定义的process节点的id启动流程。
- startProcesslnstanceByKey(String processDefinitionKey,Map<String, Object> variables):可以传入流程map参数。
- startProcesslnstanceByKey(String processDefinitionKey,String businessKey):可以传入流程业务主键。
- startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables):可以传入流程业务主键外, 也可以传入流程参数 。
startProcesslnstanceByMessage方法
- startProcessinstanceByMessage(String messageName):根据消息名称启动流程。
- startProcesslnstanceByMessage(String messageName, Map<String,Object> processVariables):使用该方法可以传入流程参数。
- startProcesslnstanceByMessage(String messageName, String businessKey):根据消息名称启动流程,可以传入业务主键。
- startProcesslnstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables):可以传入业务主键外,还可以传入流程参数。
- 在此需要注意的是,流程名称并不是message节点的id属性,而是name属性,而消息事件定义( messageEventDefinition 节点)的messageRef属性引用的是message节点的id属性。
根据租户id启动流程的方法
流程参数
- 设置与查询流程参数
- RuntimeService的setVariable和setVariableLocal方法,允许传入基本类型参数,也允许传入序列化对象。对于RuntimeService中的设置参数的方法,需要传入执行流的ID,查询流程参数也需要提供执行流的ID与参数名称。
- setVariable(String executionId, String variableName, Object value)
- setVariables(String executionId, Map<String, ? extends Object> variables)
- setVariableLocal(String executionId, String variableName, Object value)
- setVariablesLocal(String executionId, Map<String, ? extends Object> variables)
- RuntimeService的setVariable和setVariableLocal方法,允许传入基本类型参数,也允许传入序列化对象。对于RuntimeService中的设置参数的方法,需要传入执行流的ID,查询流程参数也需要提供执行流的ID与参数名称。
- 流程参数的作用域
- 使用setVariableLocal方法时,流程参数只作用于设置的执行流,一旦该执行流结束,该参数将失效。使用setVariable方法设置的参数,使用getVariableLocal方法不能获取,而使用setVariableLocal设置的参数,则可以使用getVariable方法获取。
- 设置与查询流程参数
流程操作
流程触发
在工作流程中,对于用户任务,可以使用TaskService的complete方法将当前流程节点的任务完成,完成后流程就会向前进行,而对于receiveTask等流程节点,则可以使用trigger方法将其触发,使流程往前进行。
- trigger(String executionId):触发流程中的等待节点,让流程往下执行。
- trigger(String executionId, Map<String, Object> processVariables):可以设置流程参数。
- trigger(String executionld, Map<String, Object> processVariables, Map<String, Object> transientVariables):可以设直临时参数 。
触发信号事件
- 捕获(Catching)事件:如果在一个流程中定义了Catching事件节点,则流程执行到该节点时,会一直等待触发的信号,直到接收到相应的信号后,流程才继续向前执行。
- 在Catching事件中,如果希望流程继续往下执行,可以使用RuntimeService的signalEventReceived方法抛出信号, 那么Catching事件节点就会捕获到相应的信号,让流程继续往下执行。当流程到达信号Catching事件时,事件表( ACT_RU_EVENT_SUBSCR)中会产生相应的事件描述数据,对应的EVENT_TYPE_字段值为signal。
- 抛出(Throwing)事件:如果在一个流程中定义了Throwing事件,则当流程执行到该节点时,该事件节点会自动往下执行,并不需要任何的信号指示。
- 捕获(Catching)事件:如果在一个流程中定义了Catching事件节点,则流程执行到该节点时,会一直等待触发的信号,直到接收到相应的信号后,流程才继续向前执行。
触发消息事件
Activiti中除了提供了信号事件节点外,还提供了消息事件节点。可以使用messageEventDefinition元素定义一个消息事件,该元素可以被定义在startEvent和intermediateCatchEvent元素中。如果在startEvent中定义了消息事件, 就可以使用RuntimeService的startProcessInstanceByMessage方法来启动流程;如果在interrnediateCatchEvent元素
下定义了消息事件,那么就意味着该消息事件是一个Catching事件。换言之,当执行流执行到该节点时, 会一直等待触发的消息,直到收到触发的消息后, 执行流才会继续往下进行,流程到达消息Catching事件时,会在事件表中产生事件描述数据,对应的EVENT_TYPE_字段值为 message。
当执行流遇到消息事件时,可以使用RuntirnService的messageEventReceived方法向其发送信号,通知流程引擎该事件被接收。
中断与激活流程
流程表使用SUSPENSION_STATE字段来保存流程的中断状态,若该字段值为1,则表示该流程为活跃状态;如果值为2 ,则表示该流程为中断状态。RuntimeService中提供了中断流程(suspendProcesslnstanceByld)和激活流程( activateProcessInstanceByld)的方法,在调用这两个方法时,需要提供流程实例的ID。
java// 暂停 suspendProcessInstanceById(String processInstanceId); // 激活 activateProcessInstanceById(String processInstanceId);
删除流程
- RuntimeService的deleteProcesslnstance(String processlnstanceld, String deleteReason)方法,调用该方法时只需要提供流程实例的ID和删除原因字符串即可。流程实例被删除后,相关的数据将会从原来运行时的表中被删除,将这部分数据存放到历史表中,其中包括流程实例、流程任务和流程节点等数据。
流程数据查询
- 执行流查询
- 使用RuntimeService的createExecutionQuery方法可以得到一个ExecutionQuery对象,使用该对象可以根据执行流的相 关数据查询执行流,这些数据包括执行流的参数、执行流的活动状态、执行流信号事件和执行流消息事件等。
- 流程实例查询
- 使用RuntimeService中的createProcesslnstanceQuery方法获取ProcesslnstanceQuery实例,ProcesslnstanceQuery提供的设置查询条件的方法与ExecutionQuery提供的类似。
- 执行流查询
二、相关代码演示
package com.laogoubi.coreapi;
import com.google.common.collect.Maps;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceBuilder;
import org.activiti.engine.test.ActivitiRule;
import org.activiti.engine.test.Deployment;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
/**
* @ClassName RuntimeServiceTest
* @Description RuntimeService
* @Author eastern
* @Date 2020/7/1 下午9:41
* @Version 1.0
**/
public class RuntimeServiceTest {
private static final Logger logger = LoggerFactory.getLogger(RuntimeServiceTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti.cfg.xml");
@Test
@Deployment(resources = {"diagrams/my-process.bpmn20.xml"})
public void testStartProcess(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
Map<String, Object> params = Maps.newHashMap();
params.put("key1", "value1");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process", params);
logger.info("processInstance = {}", processInstance);
}
@Test
@Deployment(resources = {"diagrams/my-process.bpmn20.xml"})
public void testStartProcessId(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessDefinition processDefinition =
activitiRule.getRepositoryService().createProcessDefinitionQuery().singleResult();
Map<String, Object> params = Maps.newHashMap();
params.put("key1", "value1");
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), params);
logger.info("processInstance = {}", processInstance);
}
@Test
@Deployment(resources = {"diagrams/my-process.bpmn20.xml"})
public void testStartProcessInstanceBuilder(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessDefinition processDefinition =
activitiRule.getRepositoryService().createProcessDefinitionQuery().singleResult();
Map<String, Object> params = Maps.newHashMap();
params.put("key1", "value1");
ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
ProcessInstance processInstance = processInstanceBuilder.businessKey("businessKey001").processDefinitionId(processDefinition.getId()).variables(params).start();
logger.info("processInstance = {}", processInstance);
}
@Test
@Deployment(resources = {"diagrams/my-process.bpmn20.xml"})
public void testVariables(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
Map<String, Object> params = Maps.newHashMap();
params.put("key1", "value1");
params.put("key2", "value2");
params.put("key3", "value3");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process", params);
logger.info("processInstance = {}", processInstance);
runtimeService.setVariable(processInstance.getId(), "key1", "value1_");
Map<String, Object> variables = runtimeService.getVariables(processInstance.getId());
logger.info("variables = {}", variables);
}
@Test
@Deployment(resources = {"diagrams/my-process.bpmn20.xml"})
public void testProcessInstanceQuery(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process");
logger.info("processInstance = {}", processInstance);
ProcessInstance processInstance1 =
runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getId()).singleResult();
}
@Test
@Deployment(resources = {"diagrams/my-process.bpmn20.xml"})
public void testExecutionQuery(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process");
logger.info("processInstance = {}", processInstance);
List<Execution> executions = runtimeService.createExecutionQuery().listPage(0, 100);
for (Execution execution : executions) {
logger.info("execution = {}", execution);
}
}
@Test
@Deployment(resources = {"diagrams/my-process-trigger.bpmn20.xml"})
public void testTrigger(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process");
Execution execution = runtimeService.createExecutionQuery().activityId("someTask").singleResult();
logger.info("someTask前 = {}", execution);
runtimeService.trigger(execution.getId());
execution = runtimeService.createExecutionQuery().activityId("someTask").singleResult();
logger.info("someTask后 = {}", execution);
}
@Test
@Deployment(resources = {"diagrams/my-process-signal-received.bpmn20.xml"})
public void testSignalEventReceived(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process");
Execution execution =
runtimeService.createExecutionQuery().signalEventSubscriptionName("my-signal").singleResult();
logger.info("execution = {}", execution);
runtimeService.signalEventReceived("my-signal");
execution = runtimeService.createExecutionQuery().signalEventSubscriptionName("my-signal").singleResult();
logger.info("execution = {}", execution);
}
@Test
@Deployment(resources = {"diagrams/my-process-message-received.bpmn20.xml"})
public void testMessageEventReceived(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("my-process");
Execution execution =
runtimeService.createExecutionQuery().messageEventSubscriptionName("my-message").singleResult();
logger.info("execution = {}", execution);
runtimeService.messageEventReceived("my-message", execution.getId());
execution = runtimeService.createExecutionQuery().messageEventSubscriptionName("my-message").singleResult();
logger.info("execution = {}", execution);
}
@Test
@Deployment(resources = {"diagrams/my-process-message.bpmn20.xml"})
public void testMessage(){
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByMessage("my-message");
logger.info("processInstance = {}", processInstance);
}
}
相关资源
my-process-trigger.bpmn20.xml
xml<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <process id="my-process"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask" /> <receiveTask id="someTask"></receiveTask> <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end" /> <endEvent id="end" /> </process> </definitions>
my-process-message-received.bpmn20.xml
xml<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <message id="messageStart" name="my-message"></message> <process id="my-process"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="message-received" /> <intermediateCatchEvent id="message-received"> <messageEventDefinition messageRef="messageStart" ></messageEventDefinition> </intermediateCatchEvent> <sequenceFlow id="flow2" sourceRef="message-received" targetRef="end" /> <endEvent id="end" /> </process> </definitions>
my-process-signal-received.bpmn20.xml
xml<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <signal id="signalStart" name="my-signal"></signal> <process id="my-process"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="signal-received" /> <intermediateCatchEvent id="signal-received"> <signalEventDefinition signalRef="signalStart"></signalEventDefinition> </intermediateCatchEvent> <sequenceFlow id="flow2" sourceRef="signal-received" targetRef="end" /> <endEvent id="end" /> </process> </definitions>
my-process-message.bpmn20.xml
xml<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <message id="messageStart" name="my-message"></message> <process id="my-process"> <startEvent id="start"> <messageEventDefinition messageRef="messageStart" ></messageEventDefinition> </startEvent> <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask" /> <userTask id="someTask" name="Activiti is awesome"></userTask> <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end" /> <endEvent id="end" /> </process> </definitions>