Activiti(工作流-2)执行过程解析

(转载https://blog.csdn.net/lp2388163/article/details/98206543?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduend~default-1-98206543.nonecase&utm_term=activiti%20%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F&spm=1000.2123.3001.4430)

1.activiti工作流执行过程解析

[执行过程interceptor、cmd、listener、handler]

1.activiti核心对象解释:

ProcessEngine:

ProcessEngines.getDefaultProcessEngine()会在第一次调用时 初始化并创建一个流程引擎,以后再调用就会返回相同的流程引擎。 使用对应的方法可以创建和关闭所有流程引擎:ProcessEngines.init()和ProcessEngines.destroy()。

RepositoryService:

可能是使用Activiti引擎时最先接触的服务。 它提供了管理和控制发布包和流程定义的操作。它包含了一个流程每个环节的结构和行为。可以自由选择把任意资源包含到发布包中。 既可以把一个单独的BPMN 2.0 xml文件放到发布包里,也可以把整个流程和相关资源都放在一起。发布一个发布包,意味着把它上传到引擎中,所有流程都会在保存进数据库之前分析解析好。

TaskService:

任务是由系统中真实人员执行的,所有与任务有关的功能都包含在TaskService中:

查询分配给用户或组的任务。

创建独立运行任务。这些任务与流程实例无关。

手工设置任务的执行者,或者这些用户通过何种方式与任务关联。

认领并完成一个任务。认领意味着一个人期望成为任务的执行者, 即这个用户会完成任务。完成意味着“做这个任务要求的事情”。 通常来说会有很多种处理形式。

IdentityService:

它可以管理(创建,更新,删除,查询...)群组和用户。

HistoryService:

提供了Activiti引擎手机的所有历史数据。 在执行流程时,引擎会保存很多数据(根据配置),比如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个服务主要通过查询功能来获得这些数据。

RuntimeService:

执行管理,包括启动,推进,删除流程实例等操作,在流程运行时对流程实例进行管理与控制。

2.表名前缀解释:

ACT_GE_*: “GE”代表“General”(通用),用在各种情况下。

ACT_HI_*: “HI”代表“History”(历史),这些表中保存的都是历史数据,比如执行过的流程实例、变量、任务,等等。

指定保存历史记录级别:

   Ønone: 不保存任何历史记录,可以提高系统性能;

   Øactivity:保存所有的流程实例、任务、活动信息;

   Øaudit:也是Activiti的默认级别,保存所有的流程实例、任务、活动、表单属性;

   Øfull:最完整的历史记录,除了包含audit级别的信息之外还能保存详细,例如:流程变量。

ACT_ID_*: “ID”代表“Identity”(身份),这些表中保存的都是身份信息,如用户和组以及两者之间的关系。如果Activiti被集成在某一系统当中的话,这些表可以不用,可以直接使用现有系统中的用户或组信息;

ACT_RE_*: “RE”代表“Repository”(仓库),这些表中保存一些‘静态’信息,如流程定义和流程资源(如图片、规则等);

ACT_RU_*: “RU”代表“Runtime”(运行时),这些表中保存一些流程实例、用户任务、变量等的运行时数据。Activiti只保存流程实例在执行过程中的运行时数据,并且当流程结束后会立即移除这些数据,这是为了保证运行时表尽量的小并运行的足够快;

3.activiti异常声明:

ActivitiWrongDbException:当Activiti引擎发现数据库版本号和引擎版本号不一致时抛出。

ActivitiOptimisticLockingException:对同一数据进行并发方法并出现乐观锁时抛出。

ActivitiClassLoadingException:当无法找到需要加载的类或在加载类时出现了错误(比如,JavaDelegate,TaskListener等。

ActivitiObjectNotFoundException:当请求或操作的对应不存在时抛出。

ActivitiIllegalArgumentException:这个异常表示调用Activiti API时传入了一个非法的参数,可能是引擎配置中的非法值,或提供了一个非法制,或流程定义中使用的非法值。

ActivitiTaskAlreadyClaimedException:当任务已经被认领了,再调用taskService.claim(...)就会抛出。

4.Demo流程图:

Demo代码演示:

// 创建流程引擎对象

private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 流程定义

processEngine.getRepositoryService()

    .createDeployment()

    .name("test")

    .addClasspathResource("activitiTest.bpmn")

    .deploy();

// 流程启动

ProcessInstance pi = processEngine.getRuntimeService()

    .startProcessInstanceByKey("activitiTest");

System.out.println("pId: " + pi.getId() + ", pName: " + pi.getName());

// 查询指定代理人的任务,进行执行
TaskService taskService = processEngine.getTaskService();

// 根据assignee查询员工任务

List tasks = taskService.createTaskQuery().taskAssignee("员工").list();

for (Task task : tasks) {

System.out.println("taskId: " + task.getId() + ", taskAssignee: " + task.getAssignee());

// 添加员工基本信息

taskService.setVariable(task.getId(), "请假人", "原野" + task.getId());

taskService.setVariable(task.getId(), "请假时长", 7);

taskService.setVariable(task.getId(), "日期", new Date());

// 提交申请(执行任务)

taskService.complete(task.getId());

}

/提交申请后,任务流向下一个节点/

Task task1 = taskService.createTaskQuery().taskAssignee("上司").singleResult();

System.out.println("taskId: " + task1.getId() + ", taskAssignee: " + task1.getAssignee() + ", taskName: " + task1.getName() + ", taskTime: " + task1.getCreateTime());

// 上司查看员工基本信息

String name = (String) taskService.getVariable(task1.getId(), "请假人");

Integer time = (Integer) taskService.getVariable(task1.getId(), "请假时长");

Date date = (Date) taskService.getVariable(task1.getId(), "日期");

System.out.println("name: " + name + ", time: " + time + ", date: " + date);

// 上司审批完成

taskService.complete(task1.getId());
// 流程走到结束事件,流程结束!

以上是一个简单的流程Demo,演示一个员工申请请假,上司审批的过程。

首先需要定义bpmn流程图,然后针对该流程图(xml)的操作是:

定义流程 -> 启动流程 ->执行流程步骤 -> 结束

在这个过程中,先通过RepositoryService对象对流程进行定义,流程的xml信息等会被加载到数据库表中,并创建流程解析和部署的数据。然后启动流程通过RuntimeService对象指定xml的 id启动,对应流程解析表的key。根据定义流程的信息创建对应的流程实例,流程任务。最后通过TaskService对象查询任务执行任务等,执行完成后流程结束。

  1. 流程发布

简述:

首先创建一个ProcessEngine的流程引擎对象,该对象创建过程中会检查数据库中是否存在了activiti需要的基础表,不存在则创建。

根据RepositoryService创建部署对象,通过addClasspathResource().deploy对指定的bpmn文件进行加载,在数据库中保存这些基本信息后,流程发布完成,数据库中存储了xml和流程发布的基本信息后,可以进行流程启动。

细节:

在创建流程引擎的过程中,会首先判断数据库中是否存在了基本的表结构,如果没有就会初始化表结构(创建28张表/activiti6.0之前版本是23张)

之后往ACT_GE_PROPERTY(系统相关属性表)插入四条数据,保存工作流引擎的基本信息。如果原本的表结构以及系统相关属性纪录已经存在,则不做上述操作。

创建流程引擎后的ACT_GE_PROPERTY,字段分别是属性名,属性值,版本号

在定义流程的过程中,ACT_GE_PROPERTY表中的next.dbid的value,作为ACT_RE_DEPLOYMENT(流程部署信息表)的主键id,生成一条流程部署纪录。

同时往ACT_GE_BYTEARRAY(流程资源表)和ACT_RE_PROCDEF(流程解析表)插入一条纪录,这两条纪录都关联部署信息表的id。

然后对ACT_GE_PROPERTY表纪录修改,修改后的next.dbid作为下一个流程部署信息纪录的主键。

如果对同一个流程部署两次的话,ACT_GE_BYTEARRAY(流程资源表),ACT_RE_PROCDEF(流程解析表),ACT_GE_PROPERTY(流程部署表)都会相应的增加一条纪录。在ACT_RE_PROCDEF表中有VERSION字段,在根据key启动流程的时候是基于VERSION最大的记录启动。

删除一个流程定义:

因为指定了级联, ACT_RE_DEPLOYMENT表id为10001这条纪录被删除,ACT_GE_BYTEARRAY,ACT_RE_PROCDEF关联这条纪录的数据也被删除。

  1. 流程的启动

简述:

因为在上一步已经发布了流程,那么在这里就是针对发布的流程进行一个启动,发布的流程xml信息保存在了数据库中,这里通过RuntimeService对象的startProcessInstanceByKey()来启动流程(也可以通过其他方法),参数为xml的的id,启动流程后该流程实例被生成,可以针对这个流程实例进行任务的执行,驳回,查看任务,分派任务等操作。

细节:

启动流程一般是根据startProcessInstanceByKey()来启动流程,也就是ACT_RE_PROCDEF(流程解析表)的Key_字段,XML文件中的id。也可以根据startProcessInstanceById()等来启动(流程解析表主键id)。

整个启动对数据库表的操作过程为:

  1. 根据startProcessInstanceByKey()拿Key_查询流程解析表,获得流程解析表中的一条数据,如果存在重复Key_数据,取Max(版本号)的一条。

  2. 因为ACT_RE_PROCDEF(流程解析表)关联了ACT_RE_DEPLOYMENT(部署信息表),而ACT_GE_BYTEARRAY(流程资源表)又关联了ACT_RE_DEPLOYMENT,所以在流程启动时就拿到了发布流程的所有信息。

  3. 开始启动流程,往ACT_HI_PROCINST(历史流程实例)创建历史实例记录,ACT_HI_ACTINST(历史节点)创建历史节点记录。ACT_HI_TASKINST(历史任务表),ACT_HI_IDENTITYLINK(历史流程人员表)添加纪录(如果存在)

历史实例:

历史节点:

历史任务:

历史流程人员:

  1. 在ACT_RU_EXECUTION(运行时流程实例表)创建流程实例记录,如果该节点存在任务则在ACT_RU_TASK(运行时任务表)创建任务记录,ACT_RU_IDENTITYLINK(运行流程人员表)创建流程中任务办理人员记录。如果进行了setVariables()则在ACT_HI_VARINST(历史变量表),ACT_RU_VARIABLE(运行变量表)添加变量信息

运行实例:

运行任务:

运行流程人员:

历史变量以及运行时变量:

其中所有历史纪录表关联了实例表,而实例表关联流程解析表id

运行时表围绕实例表和解析表关联,运行实例表关联解析表id

  1. 任务管理

简述:

在流程启动后,流程走向了用户任务节点,那么该节点就会有一条在ACT_RU_TASK(运行任务)中的代办任务记录,通过创建查询对象,根据assignee查询表中ASSIGNEE_为员工的记录,查到这些任务后,通过setVarable往ACT_RU_VARIABLE,ACT_HI_VARINST添加变量信息,然后通过complete()完成指定的任务,流程流向下一个节点。下一个节点同上一样,查询自己的任务,是否完成(批准),查看参数变量。

细节:

首先会根据api去ACT_RU_TASK(运行任务表)查询指定的任务,这里是根据taskAssignee(),也就是指定人查询,查询的条件为运行任务表中的ASSIGNEE_字段,查到的任务返回后,得到taskId。

setVariable(),意味着往ACT_HI_VARINST,ACT_RU_VARIABLE变量表中添加变量信息,该表关联流程实例表,运行时变量表在执行完后会删除,历史纪录会保存下来。

执行complete(taskId)方法时,指定的运行时任务完成,那么ACT_RU_TASK表中删除该条任务记录,历史纪录表中update结束时间,流程流向下一个节点,如果下一个节点是任务节点,那么又会创建新的任务,以及历史任务。

原文地址:https://www.cnblogs.com/jnnleo/p/13884931.html