首页 > 其他分享 >工作流引擎 Activiti 学习笔记(一)

工作流引擎 Activiti 学习笔记(一)

时间:2022-08-30 16:44:49浏览次数:85  
标签:定义 Activiti ActivityImpl 流程 笔记 引擎 执行 节点

一、什么是工作流

1. 概念

  • 工作流(Workflow)是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行。

2. 工作流的实现方式

  • 在工作流引擎出现之前,我们为了实现流程控制,通常的做法就是通过状态子段跟踪流程的变化清空。
    • 对于不同角色的用户,可以通过状态字段的取值来决定是否显示记录。
    • 针对有权限查看的记录,当前用户通过设置状态字段的值来决定该记录是否审批通过。
    • 虽然通过状态字段做到了流程控制,但是当流程发生变更的时候,这种方式编写的代码也要进行调整。
  • 通过工作流引擎(Activiti)实现工作流。
    • Activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言 BPMN2.0 进行定义,业务流程按照预先定义的流程进行执行,由 Activiti 管理业务流程,减少了业务系统由于流程变更进行系统升级改造的工作量,从而提高了系统的健壮性,同时也减少了系统开发维护的成本。

二、Activiti 简介

1. 介绍

  • Activiti是一个工作流引擎,Activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言 BPMN2.0 进行定义,业务流程按照预先定义的流程进行执行,由 Activiti 管理业务流程,减少了业务系统由于流程变更进行系统升级改造的工作量,从而提高了系统的健壮性,同时也减少了系统开发维护的成本。

2. BPMN(Business Process Modeling Notation)业务流程建模与标注

  • BPMN 是 BPM(Business Process Management 业务流程管理)及 Workflow 的建模语言标准之一。

3. Activiti 使用步骤

  1. 部署 Activiti
    • Activiti 实际上就是一堆 jar 包,业务系统通过访问 Activiti 的 API,就可以操作流程相关数据。
  2. 流程定义
    • 使用 Activiti 流程建模工具(activity-designer)定义业务流程。
  3. 流程定义部署
    • 使用 Activiti 提供的 API 把流程定义内容存储到数据库中
  4. 流程实例(Process Instance)启动
    • 启动一个流程实例表示开始一次业务流程的运行。
  5. 用户查询待办任务(Task)
    • 因为系统的业务流程已经交给 ACtiviti 管理了,所以通过 Activiti 的 API 就可以查询当前流程执行到哪个节点,当前用户需要办理什么任务,不需要开发人员自己编写 SQL 语句进行查询。
  6. 用户办理任务
    • 用户查询到待办任务后,就可以通过 Activiti 的 API 办理某个任务,任务办理完成后,任务自动进入下一个节点
  7. 流程结束
    • 当任务办理完成后没有下一个节点了,这个流程实例就完成了。

三、Activiti 设计解析

1. 流程定义解析

  • Activiti 遵循 BPMN2.0 规范,因此框架中少不了对 BPMN2.0 规范的定义文件(XML 文件)进行解析的解析类。
    • 首先通过类org.activiti.bpmn.converter.BpmnXMLConverter进行 XML 解析,解析为org.activiti.bpmn.model包下面的与各个 XML 文件对应的 POJO(Plain Ordinary Java Object 简单的 Java 对象)类。此时,这些 POJO 类仅仅只是 XML 文件的一个 Java 表达。
    • 再通过org.activiti.engine.impl.bpmn.parser.BpmnParser聚合不同的解析类,将上面步骤解析出来的 POJO 类进一步解析为可以在框架中利用的org.activiti.engine.impl.pvm.process包下面的类典型的代表就是 ActivityImpl 类。

2. 数据集中提交

  • Activiti 的持久化机制简单来说就是数据集中提交。集中提交还产生了一个额外的作用:自动提交。换句话说,在内存中的实体,如果更新了属性但是没有显示的执行刷新动作,在一个调用的生命周期结束后也会被持久化其最新的状态到数据库。下面来看下详细解释下这个集中提交机制。
    • 在 Activiti 所有运行期生成的对象都需要实现一个接口org.activiti.engine.impl.interceptor.Session,其定义如下
    • public interface Session
      {
          void flush();
          void close();
      }
      
    • 而 Session 对象则是由接口org.activiti.engine.impl.interceptor.SessionFactory中的方法进行生成,其定义如下
    • public interface SessionFactory {
          Class<?> getSessionType();
          Session openSession();
      }
      
    • 流程引擎内部持有各种 SessionFactory 实现,如果用户希望自定义的对象也可以被集中提交机制处理的话,也可以自定义注册自己的 SessionFactory 实现。
    • CommandContext 生命周期内新建的所有 Session 对象都存储在 Commandcontext 中的一个 Map<Class,Session>存储中,当一个命令执行完毕后,最终 CommandContext 的 close() 方法会被调用。当执行 CommandContext.close() 时,其内部会按照顺序执行 flushSessions() ,closeSessions() 方法。从名字可以看出,第一个方法内部就是执行所有 Session 对象的 flush() 方法,第二个方法内部就是执行所有的 Session 对象的 close() 方法。
    • 流程引擎内部有一个 Session 实现是比较特别的。也就是org.activiti.engine.impl.db.DbSqlSession实现。更新,删除,插入等操作时需要通过 DbSqlSession 来实现的,而实际上该实现会将这些操作缓存在内部。只有在执行 flush() 方法时才会真正的提交到数据库中。正是因为如此,所有的数据操作,实际上最终都是要等到执行 CommandContext.close() 时,才会真正提到到数据库。
    • 如果一个实体类在 DbSqlSession 的生命周期中被查询出来,并且其数据内容有了改变,则 DbSqlSession 在执行 flush() 方法时会自动刷新到数据库。

3. PVM 执行树

1. 核心理念

Activiti 的核心理念就是 PVM(Process Virtual Machine 流程虚拟机)。PVM 试图提供一组 API,通过 API 来描述工作流方面的各种可能性。

2. PVM对流程定义期的描述

  • PVM 将流程定义描述为流程元素的集合。再将流程元素细分为2个子类:流程节点(PvmActivity)和连线(PvmTransition)。
    • 流程节点是某一种动作表达的抽象描述。节点本身是可以嵌套的,也就是节点可以拥有子节点。
    • 连线表达是不同节点之间的转移关系。一个连线只能有一个源头节点和一个目标节点。而节点本身可以有任意多的进入连线和外出连线。

3. PVM对流程运行期的描述

  • 通过流程节点和连线,PVM 完成了对流程定义的表达。流程定义是一个流程的静态表达,流程执行则是依照流程定义启动的一个运行期表达,每一个流程执行都具备自己唯一的生命周期。流程执行需要具备以下要素:
    1. 流程节点的具体执行动作。
    2. 流程执行当前处于哪一个流程节点。
    3. 流程执行是如何从一个节点运行至下一个节点。
    4. 流程执行如何执行流程节点定义的执行动作。
  • 针对以上要素,Activiti 提供的接口
    • 针对要素 1,Activiti 提供了接口org.activiti.engine.impl.pvm.delegate.ActivityBehavior。该接口内部仅有一个 execute 方法。该接口的实现即为不同PvmActivity 节点提供了具体动作。 ActivityBehavior 有丰富的不同实现,对应了流程中丰富的不同功能的节点。每一个 PvmActivity 对象都会持有一个 ActivityBehavior 对象。
    • 针对要素 2,Activiti 提供了接口org.activiti.engine.impl.pvm.PvmExecution。该接口有一个方法 getActivity()。用以返回当前流程执行所处的流程节点(PvmActivity 对象)。
    • 针对要素 3,Activiti 提供了接口org.activiti.engine.impl.pvm.runtime.InterpretableExecution。接口方法很多,这里取和流程执行运转最重要的2个方法展开
      void take(PvmTransition transition);void take(PvmTransition transition, boolean fireActivityCompletedEvent);
      执行方法 task,议连线对象作为传入参数,这会使得流程执行该连线定义的路线。其实现逻辑应该为让流程执行定位于连线源头的活动节点,经由连线对象,到达连线目的地的活动节点。
    • 针对要素 4,实际上是由接口org.activiti.engine.impl.pvm.runtime.AtomicOperation来完成的。通过该接口的调用类,此种情况的实现者需要获取当前流程执行所处的活动节点的 ActivityBehavior 对象,执行其 execute 方法来执行节点动作。结合要素 3 和 4 ,可以看出 AtomicOperation 接口用于执行流程运转中的单一指令,例如根据连线移动,执行节点指令等。分解成单一指令的好处是易于编码和理解。这也契合接口命名中的原子一意。

4. ActivitiImpl 与作用域

  • 在解析完成后,一个流程定义中的所有节点都会被解析为 ActivityImpl 对象。ActivityImpl 对象本身可以持有事件订阅(根据BPMN2.0规范,目前有定时,消息,信号三种事件订阅类型)。因为 ActivityImpl 本身可以嵌套并且可以持有订阅,因此引入作用域概念(Scope)。一个 ActivityImpl 在以下两种情况下会被定义为作用域 ActivityImpl。
    1. 该 ActivityImpl 是可变范围,则它是一个作用域。可变范围可以理解为该节点的内容定义是可变的。比如流程定义、子流程,其内部内容是可变的。根据 BPMN 定义,可变范围有:流程定义,子流程,多实例,调用活动。
    2. 该 ActivityImpl 定义了一个上下文用于接收事件。比如:具备边界事件的 ActivityImpl ,具备事件子流程的 ActivityImpl ,事件驱动网关,中间事件捕获 ActivityImpl 。
    • 作用域是一个很重要的概念,情况 1 中作用域定义的是复杂节点的生命周期,情况 2 中作用域定义的是事件的捕获范围。

5. ExecutionEntity

  • ExecutionEntity 的含义是一个流程定义被启动后的执行实例,代表着流程的运行期状态。在 Activiti 的设计中,事件订阅,流程变量等都是与一个具体的 ExecutionEntity 相关的。其本身有几个重要的属性:
    • isScope:该属性为真时,意味该执行实例在执行一个具备作用域的 ActivityImpl 节点或者执行一个流程定义。
    • isConcurrent:该属性为真时,意味与该执行实例正在执行的活动节点同属相同作用域的节点可能正并发被其他执行实例执行(比如并行网关后面的2个并行任务)。
    • isActive:该属性为真时,意味该执行实例正在执行一个简单 ActivityImpl(不包含其他 ActivityImpl 的 ActivityImpl)
    • isEventScope:该属性为真时,意味该执行实例是为了后期补偿而进行的变量保存所创建的执行实例。由于流程执行中的变量都需要与ExecutionEntity 挂钩,而补偿是需要原始变量的快照。为了满足这个需求,创建出一个专用于此的 ExecutionEntity。
    • activityId:该 ExecutionEntity 正在执行的 ActivityImpl 的 id 。正在执行意味着几种情况:进入该节点,执行该节点动作,离开该节点。如果是等待子流程的完成,则该属性为 null。
  • 上面对 ExecutionEntity 的解释仍然抽象。如果直观的看,可以认为 ExecutionEntity 是某一种生命周期的体现,其内部属性随着不同的情况而变化.
  • 随着流程的启动,会创建一个 ExecutionEntity 对象。该 ExecutionEntity 生命周期与整个流程相同,而其中的 isScope 和 isConcurrent 在创建之初固定,并且不会改变。而 isActive 和 activityId 随着流程的推进则会不断变化。
  • ExecutionEntity 是用来反映流程的推进情况的,实际上,往往一个 ExecutionEntity 不足以支撑全部的 BPMN 功能。因此实现上,Activiti 是通过一个树状结构的 ExecutionEntity 结构来反映流程推进情况。创建之初的 ExecutionEntity 对象随着流程的推进会不断的分裂和合并,ExecutionEntity 树也会不断的生长和修剪。在流程的推进过程中会遇到4种基本情况
    1. 单独的非作用域节点
    2. 单独的作用域节点
    3. 并发的非作用域节点
    4. 并发的作用域节点
      image

4. 流程启动

1. 流程说明

  • 流程启动依靠的是命令类:org.activiti.engine.impl.cmd.StartProcessInstanceCmd该命令的整体流程如下:
    image

2. 流程定义实体创建流程实例

image

原文:https://zhuanlan.zhihu.com/p/98715989

标签:定义,Activiti,ActivityImpl,流程,笔记,引擎,执行,节点
From: https://www.cnblogs.com/whitegogogo/p/16638497.html

相关文章