Skip to content
一、RuntimeService介绍
  • RuntimeService

    • 启动流程及对流程数据的控制。
    • 流程实例【ProcessInstance】和执行流【Execution】查询。
    • 触发流程操作、接受消息和信号。
  • RuntimeService启动流程及变量管理

    • 启动流程的常用方式(id,key,message)
    • 启动流程可选参数(businessKey,variables,tenantId)
    • 变量(variables)的设置和获取
  • 流程实例与执行流

    • 流程实例(ProcessInstance)表示一次工作流业务的数据实体。
    • 执行流(Execution)表示流程实例中具体的执行路径。
    • 流程实例接口继承于执行流
  • 流程触发

    • 使用trigger触发ReceiveTask节点
    • 触发信号捕获事件signalEventReceived【全局触发信号】
    • 触发消息捕获事件messageEventReceived【针对流程触发消息】
  • 相关方法

    image-20200721093628194

    image-20200721093739493

    image-20200721093826288

  • 相关详解

    • 流程实例与执行流概念

      • 在Activiti中,启动了一个流程,会创建一个流程实例(Processlnstance),每个流程实例至少会有一个执行流(Execution) 。当流程实例没有流程分支时,一般情况下只会存在一个执行流;假设流程出现两个分支,此时Activiti将会有三个执行流,第一个为原来流程的主执行流,而其余两个为子执行流。
    • 流程实例和执行流对象

      • Processlnstance是一个接口,一个Processlnstance实例表示一个流程实例,Processlnstance实际上是执行流(Execution)的子接口,流程实例也是一个执行流。Processlnstance中有Execution没有的属性,例如流程定义和业务主键。当得到的是一个Processlnstance实例时,就将其看作一个流程实例;当得到一个Execution实例时,它就是一个执行流。流程实例与执行流的数据保存在执行表ACT_RU_EXECUTION中,对应的映射实体为ExecutionEntitylmpl。
    • 启动流程

      • startProcesslnstanceByld方法

        image-20200721095151024

        • 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方法

        image-20200721100357656

        • 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方法

        image-20200721101757939

        • 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启动流程的方法

        image-20200721102414855

        image-20200721102456058

    • 流程参数

      • 设置与查询流程参数
        • 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)
      • 流程参数的作用域
        • 使用setVariableLocal方法时,流程参数只作用于设置的执行流,一旦该执行流结束,该参数将失效。使用setVariable方法设置的参数,使用getVariableLocal方法不能获取,而使用setVariableLocal设置的参数,则可以使用getVariable方法获取。
    • 流程操作

      • 流程触发

        在工作流程中,对于用户任务,可以使用TaskService的complete方法将当前流程节点的任务完成,完成后流程就会向前进行,而对于receiveTask等流程节点,则可以使用trigger方法将其触发,使流程往前进行。

        image-20200721104556697

        • 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事件,则当流程执行到该节点时,该事件节点会自动往下执行,并不需要任何的信号指示。
      • 触发消息事件

        Activiti中除了提供了信号事件节点外,还提供了消息事件节点。可以使用messageEventDefinition元素定义一个消息事件,该元素可以被定义在startEvent和intermediateCatchEvent元素中。如果在startEvent中定义了消息事件, 就可以使用RuntimeService的startProcess­InstanceByMessage方法来启动流程;如果在interrnediateCatchEvent元素

        下定义了消息事件,那么就意味着该消息事件是一个Catching事件。换言之,当执行流执行到该节点时, 会一直等待触发的消息,直到收到触发的消息后, 执行流才会继续往下进行,流程到达消息Catching事件时,会在事件表中产生事件描述数据,对应的EVENT_TYPE_字段值为 message。

        当执行流遇到消息事件时,可以使用RuntirnService的messageEventReceived方法向其发送信号,通知流程引擎该事件被接收。

        image-20200721140936083

      • 中断与激活流程

        • 流程表使用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提供的类似。
二、相关代码演示
java
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>

Released under the MIT License.