[Camunda]流程引擎从入门到入行 - 运行时服务runtimeService

Camunda流程引擎系列

四、运行时服务类 - RuntimeService



前言

该服务类包含了许多与实例相关的服务,流程定义好的规则开始运转时,就是我们本次分享的主要内容。


一、RuntimeServiceImpl

我们对运行时服务的调用,基本都可以基于该类进行操作,官方提供了非常多的方法,有兴趣的小伙伴可以搜索 RuntimeServiceImpl 看看源码,在org.camunda.bpm.engine.impl包下。

派生类

  • 可根据不同API启动实例,并返回ProcessInstance对象;
  • 可异步删除所有实例,并返回Batch对象;
  • 可获取变量信息,并返回VariableMap对象;
  • 可获取变量信息,并返回Map<String, Object>对象;
  • 可获取单个变量信息,并返回TypedValue;
  • 可查询执行实例,并返回ExecutionQuery对象;
  • 可自定义SQL查询并执行实例,并返回NativeExecutionQuery对象;
  • 可查询流程实例信息,并返回ProcessInstanceQuery对象;
  • 可自定义SQL查询流程实例信息,并返回NativeProcessInstanceQuery对象;
  • 可查询Incident相关信息,并返回Incident对象;

启动实例方式

  • processDefinitionKey
  • processDefinitionKey + 租户ID
  • messageName + 租户ID
  • messageName
  • processDefinitionId

二、流程定义

1.定义

流程定义:通过资源文件,获取已事先定义好的流程规则信息。
执行实例:发起流程定义,可以认为流程定义就像定义了一个类,而执行实例就是生成了一个对象。
流程实例:一个流程的最长分支,就好比项目管理里面的关键路径。

public interface ProcessInstance extends Execution

启动流程时会首先创建流程实例,如果存在子流程、多实例、并行网关,则会再次创建执行实例。流程运转的过程中永远执行的时自己对应的执行实例。当所有执行实例按照规则执行完毕之后,则流程实例随之结束。

Camunda用ProcessInstance对象去描述流程执行的每一个节点,流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

一个流程中,执行对象可以是多个,执行实例在某个活动节点时,需要我们通过特定API去完成,然后执行实例继续往下走。

一个实例运行的简单过程:

  1. 启动实例;
  2. 创建实例;
  3. 更新实例;
  4. 完成实例。

稍微复杂一点的如存在并行网关的话,流程实例就是这样的:
在这里插入图片描述

2. 启动流程

RuntimeService有很多启动流程的API,我们演示其中一种,因为不同的API主要差别在于传参的不同,传参不同主要是业务逻辑的不同,但是其本质大同小异。

获取runtimeService

private RuntimeService runtimeService = PnxProcessEngine.INSTANCE.getProcessEngine().getRuntimeService();

根据key启动实例

这个KEY可以在数据库表 ACT_RE_PROCDEF 的KEY_字段查看到,当然也可以在流程文件中查到,或者通过查询接口查到。

    public ProcessInstance startProcess(String key) {
        return runtimeService.startProcessInstanceByKey(key);
    }

实例启动后,程序会返回ProcessInstance 的对象。
下面是我们的测试代码,可以看看返回的对象包含什么样的数据

    @Test
    void startProcess() {
        String key = "Process_0iplu3k";
        ProcessInstance processInstance = pnxRuntimeService.startProcess(key);
        processInstance.getId();
        System.out.println("id is : " + processInstance.getId());
        System.out.println("getBusinessKey is : " + processInstance.getBusinessKey());
        System.out.println("getRootProcessInstanceId is : " + processInstance.getRootProcessInstanceId());
        System.out.println("getProcessInstanceId is : " + processInstance.getProcessInstanceId());
    }

当流程实例启动时,以下两张表会有新的数据插入:

ACT_RU_EXECUTION
ACT_RU_TASK

同时会有几张历史表也会插入数据(ACT_HI_XXXX都是历史表):

ACT_HI_ACTINST
ACT_HI_TASKINST
ACT_HI_PROCINST
ACT_HI_IDENTITYLINK


完成Task

一个实例启动过后,对应的任务需要完成才会走入下一个节点,这时候我们会有大量对Task的操作,从产品的角度来看,一个任务启动会根据规则分配到人,然后该用户获取自己的任务列表,进行操作后完成该任务。

那么我们看看这几个操作会涉及哪几个API,以及用测试代码做一下测试看看,然后对完成一个任务时会操作哪些数据做一些讲解。

/**
 * @author zhaopeng01
 * @version 1.0
 * @title: PnxTaskServiceImpl
 * @projectName phoenix-camunda
 * @description: TODO
 * @date 2020/11/1421:41
 */
@Service
public class PnxTaskServiceImpl {
    private TaskService taskService = PnxProcessEngine.INSTANCE.getProcessEngine().getTaskService();

    public List<Task> getTasks(int first, int max) {
        return taskService.createTaskQuery().listPage(first, max);
    }

    public void assignTask(String taskId, String assignee) {
        taskService.setAssignee(taskId, assignee);
    }

    public List<Task> getTasksByAssignee(String assignee, int first, int max) {
        return taskService.createTaskQuery().taskAssignee(assignee).listPage(first, max);
    }

    public void completeTask(String taskId) {
        taskService.complete(taskId);
    }

    public Task getTaskById(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }
}

测试代码:
/**
 * @author zerozhao
 * @version 1.0
 * @title: PnxTaskServiceImplTest
 * @projectName phoenix-camunda
 * @description: TODO
 * @date 2020/11/1421:50
 */
@SpringBootTest
class PnxTaskServiceImplTest {
    @Autowired
    PnxTaskServiceImpl taskService;

    private String taskId = "1604";
    private String assignee = "zero";

    @Test
    @Order(0)
    void getTasks() {
        System.out.println(taskService);
        List<Task> tasks = taskService.getTasks(0, 5);
        tasks.stream().forEach(task -> {
            taskId = task.getId();
        });
    }

    @Test
    @Order(1)
    void assignTask() {
        taskService.assignTask(taskId, assignee);
    }

    @Test
    @Order(2)
    void getTasksByAssignee() {
        List<Task> tasks = taskService.getTasksByAssignee(assignee, 0, 5);
        tasks.stream().forEach(task -> {
            assertEquals("assignee is equal.", task.getAssignee(), assignee);
        });
    }

    @Test
    @Order(3)
    void completeTask() {
        taskService.completeTask(taskId);
        Task task = taskService.getTaskById(taskId);
        assertNull("没有对应task", task);
    }
}

在这组单元测试代码中,我们会先查询任务列表,然后对该任务赋予一个执行人,接下来会完成该任务,用原任务号去查询,该任务已经没有了。
那么原任务去哪里了呢?进入历史表了,而任务表会插入一个新的任务,是我们流程定义的下一个节点。
任务的完成会涉及到多张表的数据操作,那么我们来看看分别是那几张表,这将有利于我们理解其背后的逻辑,从而更好地完成我们的业务诉求。

插入:

  • ACT_HI_TASKINST
  • ACT_HI_IDENTITYLINK(不一定有,要看用户模式)
  • ACT_HI_ACTINST
  • ACT_RU_TASK

删除:

  • ACT_RU_TASK

更新:

  • ACT_RU_EXECUTION
  • ACT_HI_ACTINST
  • ACT_HI_TASKINST

历史数据

在流程引擎中,更多的数据会记录进历史表中,我们要查询一些任务的状态或者列表,都会使用到这些历史表,而有的数据会在系统运行中,同步插入历史表与当前任务表。
我们来看看几张主要的历史表以及与之对应的当前数据表。

  • ACT_RU_EXECUTION:正在执行的信息
  • ACT_HI_PROCINST:已经执行完的历史流程实例信息
  • ACT_HI_ACTINST:所有完成的历史活动
  • ACT_RU_TASK:正在执行的任务数据
  • ACT_HI_TASKINST:已经执行完的历史任务数据

设定发起人与使用initiator

之前的流程中,我们设置了流程的当前节点执行人,但是在实际的场景中我们的流程是不是还会有一个发起人?以及每个任务节点的指派人?指派人的设定会有一点不同,并且可以将指派人作为变量传入后续的任务中。

    @Autowired
    PnxIdentityService pnxIdentityService;
    @Autowired
    PnxRuntimeServiceImpl pnxRuntimeService;

    /**
     * 指定启动用户的开启流程
     * @param authUser
     * @param processKey
     */
    public void startProcess(String authUser, String processKey) {
        pnxIdentityService.setAuthUser(authUser);
        pnxRuntimeService.startProcess(processKey);
    }

通过IdentityService来设置流程发起人。

**NOTE:**我们开启流程最好用key,不要使用id,id是系统标识,会伴随部署更新对应的值,导致系统可能走到我们预期以外的流程上去。

删除流程实例

一个流程,如果走到一半,或者别的原因,我们希望中止了,那么就可以使用流程删除,流程删除的操作也很简单,调用RuntimeService的API即可,传入流程实例的ID与删除原因。

    public void delProcess (String processId, String reason) {
        runtimeService.deleteProcessInstance(processId, reason);
    }

这个过程中会涉及到如下数据库表操作:
删除:

  • ACT_RU_TASK
  • ACT_RU_EXECUTION

更新:

  • ACT_HI_ACTINST
  • ACT_HI_PROCINST
  • ACT_HI_TASKINST

流程的挂起与激活

有时候我们不希望一个流程被删除,但是也不希望再被操作,等待以后重新恢复。
当一个流程实例挂起时,该实例下的子流程也都会挂起,所以需要慎重确认。

  • 流程定义的挂起
    /**
     * 挂起流程定义,挂起后基于该定义的流程将不能再执行,除非先激活
     *
     * @param id
     */
    public void suspendProcessDef(String id) {
        runtimeService.suspendProcessInstanceByProcessDefinitionId(id);
    }
  • 流程实例的挂起
    /**
     * 挂起流程定义,挂起后基于该定义的流程将不能再执行,除非先激活
     *
     * 两种挂起方式
     *
     * @param id
     */
    public void suspendProcessDef(String id) {
        //runtimeService.suspendProcessInstanceByProcessDefinitionId(id);
        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        processInstanceQuery.processInstanceId(id);
        runtimeService.updateProcessInstanceSuspensionState().byProcessInstanceQuery(processInstanceQuery).suspendAsync();
    }
  • 激活流程定义
    /**
     * 两种激活流程定义的方法
     * @param id
     */
    public void activeProcessDef(String id) {
        //repositoryService.activateProcessDefinitionById(id);
        repositoryService
                .updateProcessDefinitionSuspensionState()
                .byProcessDefinitionId(id)
                .includeProcessInstances(true)
                .activate();
    }

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值