Skip to content
一、ManagementService
  • 相关API

    image-20200729145512412

  • 管理服务【ManagementService】

    • 工作的产生

      • 异步任务的产生【ACT RU_JOB】

        • Java Service Task

          xml
          <serviceTask id="someTask" activiti:class="com.laogoubi.delegate.MDCErrorDelegate"></serviceTask>

          以上的配置中定义了一个serviceTask,并且为该serviceTask设置了对应的Delegate(activiti:class)。如果需要定义异步的serviceTask,则需要为serviceTask节点加入activiti:async属性,并将该属性值设置为true。自定义的JavaDelegate 类,JavaDelegate需要实现JavaDelegate接口。

          java
          public class MDCErrorDelegate implements JavaDelegate {
          
          	private static final Logger logger = LoggerFactory.getLogger(MDCErrorDelegate.class);
          
          	@Override
          	public void execute(DelegateExecution execution) {
          		logger.info("run MDCErrorDelegate");
          		throw new RuntimeException("only test");
          	}
          }
      • 定时中间事件产生的工作【ACT_RU_TIME_JOB】

        • 如果在流程定义了定时器相关节点,那么这些节点不会马上执行,有可能在某个定义的时间点上执行,这些节点会被转化为工作保存到定时器工作表【ACT_RU_TIME_JOB】中,流程引擎会定时查询该表的数据,然后将符合执行条件(时间条件)的工作取出来交由线程池执行。在流程中可以加入定时器的节点中间事件节点、流程开始事件节点和边界事件节点。

          xml
          <intermediateCatchEvent id="timerintermediatecatchevent1" name=”TimerCatchEvent”>
              <timerEventDefinition>
                  <timeDuration>PT1M</timeDuration>
              </timerEventDefinition>
          </intermediateCatchEvent>

          表示定时器将会在1分钟后触发,即1分钟后会跳过该流程节点,执行下一个节点。

      • 定时边界事件产生的工作

        • 定时边界事件( Timer Boundary Event )同样会产生定时工作。

          xml
          <boundaryEvent id="boundaryEvent1" cancelActivity="false" attachedToRef="usertask1">
              <timerEventDefinition>
                  <timeDuration>PT1M</timeDuration>
              </timerEventDefinition>
          </boundaryEvent>

          该边界事件成为了定时边界事件,并且该节点会在1分钟后被触发。

      • 定时开始事件产生的工作

        • 在开始事件中同样可以加入定时器,让其变为定时开始事件。

          xml
          <startEvent id="start">
              <timerEventDefinition>
                  <timeCycle>R5/PT10S</timeCycle>
              </timerEventDefinition>
          </startEvent>

          在开始事件中加入定时器,并且设置了开始事件会在10秒后被触发。

      • 流程抛出事件产生的工作

        • 当执行流遇到信号Catching事件时,会停留在该事件节点,一直等待信号,并且会在事件描述表(ACT_RU_EVENT_SUBSCR)中加入相应的事件描述数据。

          xml
          <intermediateCatchEvent id="signal-received">
              <signalEventDefinition signalRef="signalStart"></signalEventDefinition>
          </intermediateCatchEvent>
      • 暂停工作的产生

        • 流程定义与流程实例可以被中断,中断后,与这些流程定义、流程实例有关的工作,将会被保存到中断工作表(ACT_RU_SUSPENED_JOB)。
        • 调用流程中断方法
          • suspendProcessInstanceById
      • 无法执行的工作

        • 如果工作在执行时发生异常, 则可以重新执行, 默认情况下,工作最大执行次数为3次,可以使用ManagementService 的setJobRetries方法来设置重试次数。如果一个工作执行多次,仍然是失败的,那么Activiti就会将其写到ACT_RU_DEADLETTER_JOB表中,该表主要用来保存一些无法执行的工作。
    • 工作管理

      • Job任务查询

        工作查询对象描述对应的表
        JobQuery查询一般工作ACT_RU_JOB
        TimerJobQuery查询定时工作ACT_RU_TIMER_JOB
        SuspendedJobQuery查询中断工作ACT_RU_SUSPENDED_JOB
        DeadLetterJobQuery查询无法执行的工作ACT_RU_DEADLETTER_JOB
      • 获取工作异常信息

        • 当工作执行中出现异常时,各个工作表的EXCEPTION_STACK_ID_ 和 EXCEPTION_MSG_ 字段会保存工作执行的异常信息,使用ManagementService的几个getXXXJobExceptionStacktrace方法可以获取这些异常信息,该方法根据EXCEPTION_STACK_ID_字段所保存的值,到ACT_GE_BYTEARRAY表中查询相应的详细异常信息。
      • 转移与删除工作

        • 几个保存工作的数据表分别代表不同状态的工作,如果想要改变工作的状态,可以调用几个move方法来进行工作的转移。
        • 可以调用几个delete方法来删除工作,可以删除一般工作、定时器工作和无法执行的工作,但要注意并没有提供删除中断工作的方法。
    • 数据库管理

      • 查询引擎属性

        • Activiti会将流程引擎相关的属性配置保存到ACT_GE_PROPERTY表中,一些全局的、可能会发生改变的属性配置均会被放到该表中保存。使用ManagementService的getProperties方法可以返回这些属性及其值。
      • 数据表信息查询

        • 查询表结构元数据(TableMetaData)

          • 如果需要知道一个数据表有哪些字段以及这些字段的类型,则可以使用ManagementService的getTableMetaData方法来获取某一个数据表的基础信息,该方法返回一个TableMetaData对象,通过该对象可以得到数据表的名称、表的全部宇段名称以及各个字段的类型信息。
          • 如果需要知道一个数据表有哪些字段以及这些字段的类型,则可以使用 ManagementService的getTableMetaData方法来获取某一个数据表的基础信息,该方法返回一个TableMetaData对象,通过该对象可以得到数据表的名称、表的全部宇段名称以及各个字段的类型信息。
        • 通用表查询(TablePageQuery)

          • 对于一些非 Activiti自带的数据表,如果想对其进行数据查询,则可以使用ManagementService的 createTablePageQuery方法创建一个TablePageQuery对象,使用该对象的tableName方法可以设置到哪个表进行数据查询,再使用listPage方法返回一个TablePage对象,使用listPage方法时需要传入查询的开始索引值和查询的最大数据量。
        • 数据库操作

          • 使用ManagementService的databaseSchemaUpgrade方法可以实现对数据库的原始操作,这些操作可以由调用人自己决定,可以创建schema、创建表、删除schema和删除表等,调用该方法需要提供Connection、数据库catalog 和数据库schema参数,其中可以使用Connection的createStatement方法得到Statement对象,然后可以执行各种 SQL语句。

            java
            managementService.databaseSchemaUpgrade();
          • 执行自定义的sql查询(executeCustomSql)

    • 执行流程引擎命令(Command)

二、相关代码
  • 测试代码

    java
    package com.laogoubi.coreapi;
    
    import com.laogoubi.mapper.MyCustomMapper;
    import org.activiti.engine.ManagementService;
    import org.activiti.engine.impl.cmd.AbstractCustomSqlExecution;
    import org.activiti.engine.impl.interceptor.Command;
    import org.activiti.engine.impl.interceptor.CommandContext;
    import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    import org.activiti.engine.management.TablePage;
    import org.activiti.engine.runtime.*;
    import org.activiti.engine.test.ActivitiRule;
    import org.activiti.engine.test.Deployment;
    import org.apache.commons.lang3.builder.ToStringBuilder;
    import org.apache.commons.lang3.builder.ToStringStyle;
    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 ManagementServiceTest
     * @Description TODO
     * @Author eastern
     * @Date 2020/7/4 上午11:34
     * @Version 1.0
     **/
    public class ManagementServiceTest {
    	private static final Logger logger = LoggerFactory.getLogger(ManagementServiceTest.class);
    
    	@Rule
    	public ActivitiRule activitiRule = new ActivitiRule("activiti_job.cfg.xml");
    
    	@Test
    	@Deployment(resources = {"diagrams/my-process-job.bpmn20.xml"})
    	public void testJobQry(){
    		ManagementService managementService = activitiRule.getManagementService();
    		List<Job> jobs = managementService.createTimerJobQuery().listPage(0, 100);
    		for (Job job : jobs) {
    			logger.info("job = {}", ToStringBuilder.reflectionToString(job, ToStringStyle.JSON_STYLE));
    		}
    
    		JobQuery jobQuery = managementService.createJobQuery();
    		SuspendedJobQuery suspendedJobQuery = managementService.createSuspendedJobQuery();
    		DeadLetterJobQuery deadLetterJobQuery = managementService.createDeadLetterJobQuery();
    
    	}
    
    	@Test
    	@Deployment(resources = {"diagrams/my-process-job.bpmn20.xml"})
    	public void testTablePageQry(){
    		ManagementService managementService = activitiRule.getManagementService();
    		TablePage tablePage =
    				managementService.createTablePageQuery().tableName(managementService.getTableName(ProcessDefinitionEntity.class)).listPage(0, 100);
    		List<Map<String, Object>> rows = tablePage.getRows();
    		for (Map<String, Object> row : rows) {
    			logger.info("row = {}", row);
    		}
    	}
    
    	@Test
    	@Deployment(resources = {"diagrams/my-process-job.bpmn20.xml"})
    	public void testCustomSql(){
    		activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
    		ManagementService managementService = activitiRule.getManagementService();
    		List<Map<String, Object>> mapList =
    				managementService.executeCustomSql(new AbstractCustomSqlExecution<MyCustomMapper, List<Map<String,
    						Object>>>(MyCustomMapper.class) {
    
    			@Override
    			public List<Map<String, Object>> execute(MyCustomMapper mapper) {
    				return mapper.findAll();
    			}
    		});
    		logger.info("mapList.size = {}", mapList);
    
    		for (Map<String, Object> map : mapList) {
    			logger.info("map = {}", map);
    		}
    	}
    
    	@Test
    	@Deployment(resources = {"diagrams/my-process-job.bpmn20.xml"})
    	public void testCommand(){
    		activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
    		ManagementService managementService = activitiRule.getManagementService();
    		ProcessDefinitionEntity processDefinitionEntity =
    				managementService.executeCommand(new Command<ProcessDefinitionEntity>() {
    
    			@Override
    			public ProcessDefinitionEntity execute(CommandContext commandContext) {
    				ProcessDefinitionEntity processDefinitionEntity =
    						commandContext.getProcessDefinitionEntityManager().findLatestProcessDefinitionByKey("my" +
    								"-process");
    				return processDefinitionEntity;
    			}
    		});
    
    		logger.info("processDefinitionEntity = {}", processDefinitionEntity);
    
    	}
    
    }
  • MyCustomMapper

    java

package com.laogoubi.mapper;

import org.apache.ibatis.annotations.Select;

import java.util.List; import java.util.Map;

/**

  • @ClassName MyCustomMapper
  • @Description TODO
  • @Author eastern
  • @Date 2020/7/5 上午10:02
  • @Version 1.0 **/ public interface MyCustomMapper {
@Select("SELECT * FROM ACT_RU_TASK")
public List<Map<String, Object>> findAll();

}


- 资源

- my-process-job.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">
  			<timerEventDefinition>
  				<timeCycle>R5/PT10S</timeCycle>
  			</timerEventDefinition>
  		</startEvent>
  		<sequenceFlow id="flow1" sourceRef="start" targetRef="someTask" />
  		<userTask id="someTask" name="Activiti is awesome!" />
  		<sequenceFlow id="flow2" sourceRef="someTask" targetRef="end" />
  		<endEvent id="end" />
  	</process>
  </definitions>
  ```

Released under the MIT License.