当我们部署一个流程并启动后,Flowable会按照既定流程定义及进行节点处理以及自动流转,从一个节点执行到下一个节点,直至结束。在此过程中,系统如何处理BPMN XML文件?节点如何进行流转?本文对flowable内部源码进行解析,挖掘其引擎原理。
如上图所示为流程启动关键节点图,主要由以下几部分组成:
主要功能:通过将bpmnXML格式文件解析为程序可执行的内存对象:Process。 类似于 saga 事件驱动中的 event 。。
a. 获取流程定义 ProcessDefinition(通过入参<流程key or 流程id>找到对应的流程定义)
b. 加载解析bpmn.xml文件(工作流原始文件)
c. 生成bpmnModel(工作流描述)
d. 生成Process(工作流执行)
主要功能:流程执行过程中会添加各种拦截器,其中最为核心的是CommandInvokerInterceptor
a. LogInterceptor:当日志级别为debug时,会输出启动日志
b. SpringTransactionInterceptor
Spring事务管理,用户事务的doTransaction、commit、rollback
c. CommandContextInterceptor:执行SqlSession close方法,将数据进行持久化
d. TransactionContextInterceptor
e. BpmnOverrideContextInterceptor
f. CommandInvokerInterceptor:真正执行启动流程命令的拦截器
主要功能:完成对流程节点的执行,及找到下一个可执行的节点,直至流程运行完成。其最核心的包括DefaulFlowableEngineAgenda,该类持有operations,通过对节点操作封装为不同的Operation,进行节点的流转。
Flowable是通过命令模式 + 责任链模式完成对操作的执行,flowable启动代码中,构造ProcessEngine时会调用 init()方法进行引擎初始化,如下图所示:
启动命令通过入参的流程key or 流程定义id加载对应的流程定义数据后,初始化了启动operation操作,其核心源码如下:
StartProcessInstanceCmd.execute() 方法定义如下:其首先获取流程定义ProcessDefinition,之后通过调用startProcessInstance启动流程。
流程定义数据来源于数据表:ACT_RE_PROCDEF,其是在流程部署时写入的,注意其字段deploymentId,在作为数据表ACT_GE_BYTEARRAY的外键,关联了 流程XML原始文件。
注意在之后,通过 process.getInitialFlowElement 方法得到流程初始节点。在之后构造 Execution 实体时,设置该初始节点。
4)在方法 ProcessInstanceHelper.startProcessInstance 中,通过调用CommandContextUtil.getAgenda(commandContext).planContinueProcessOperation(execution) 将当前实例添加到操作堆栈operations中。
至此:完成了启动命令的初始化过程
该类持有变量operations,operations是个一个堆栈,在流转过程中,通过DefaultFlowableEngineAgenda一系列操作可以
将不同的操作压入栈中,然后运转过程中,将每一个操作弹出栈进行命令的执行。这里的operation指默认实现了AbstractOperation的操作类,AbstractOperation的实现类如下所示:
比如要继续流转,则压入ContinueProcessOperation,需要结束流程则需要压入 EndExecutionOperation。
ContinueProcessOperation操作对节点和顺序流分别作了处理,如下图所示:
当前元素为节点时,执行如下主要操作:
1)标记节点开始
2)执行节点监听器
3)获取节点对应行为器
4)执行行为器
当无对应的行为器时,则创建 takeOutgoingSequenceFlowsOperation 操作
1)找到当前元素后置元素,设置为当前执行元素
2)如果后置元素是节点,则直接执行
3)如果后置元素是顺序流,则构造ContinueProcessOperation操作
如下图所示为行为器的实现类,从图中可以看到我们熟悉的StartEvent、NoneEvent及ServiceTask的实现类。
在行为器执行完成对应操作后,由行为器决定是否继续向后流转节点FlowNodeActivityBehavior默认提供了leave()方法,其内部主要是构造 TakeOutgoingSequenceFlowsOperation 继续流转节点
TakeOutgoingSequenceFlowsOperation的实现分别对节点和顺序流进行了操作,如下图所示:
当前元素为节点时:
1)首先标记当前节点执行完成
2)遍历后置顺序流元素,并计算顺序流表达式属性
3)当无有效的后置顺序流元素时,则构建EndExecutionOperation,压入栈中
4)存在有效的后置顺序流元素时,则遍历顺序流并且构造 ContinueProcessOperation操作,压入栈中
1)标记当前元素结束,构造ContinueProcessOperation操作,压入栈中
其节点流转图如下:
Step 1: 在流程启动初期,operations堆栈中压入ContinueProcessOperation操作,传入的execution的当前节点为开始节点
Step 2: 取出栈顶操作元素开始节点并执,首先进行节点开始持久化操作,之后调用节点行为类执行,开始节点的行为类是 NoneStartEventActivityBehavior,如下图所示为空操作,
其并没有实现execute()方法,还是复用了父类FlowNodeActivityBehavior的execute()方法,执行leave方法,压入TakeOutgoingSequenceOperation操作,此时execution的当前节点为开始节点
Step 3: 弹出栈顶TakeOutgoingSequenceOperation(开始节点),首先进行节点结束持久化操作,之后获取开始节点的后置可用分支,压入ContinueProcessOperation堆栈,
此时execution的当前节点为 开始节点-创建变量节点顺序流
Step 4: 取出栈顶ContinueProcessOperation(开始节点-创建变量节点顺序流) 并执行,其目标节点为 创建变量节点,开始执行,首先执行节点开始持久化操作,接着执行其行为类JavaDelegate,
执行完成后,压入TakeOutgoingSequenceOperation操作,此时execution的当前节点为创建变量节点
计算节点后置节点以及其他逻辑后,压入操作类,此时execution的当前节点为开始节点–>创建变量的连线。
Step 5: 弹出栈顶TakeOutgoingSequenceOperation(创建变量节点),首先进行节点结束持久化操作,之后获取创建变量节点的可用分支,压入ContinueProcessOperation堆栈,
此时此时execution的当前节点为创建变量节点-结束事件顺序流
Step 6: 弹出栈顶ContinueProcessOperation(创建变量节点-结束事件),其目标节点为结束事件,开始执行,首先进行节点开始持久化操作,接着执行其行为类 NoneEndEventActivityBehavior,如下图可得,
结束事件行为器构造了TakeOutgoingSequenceOperation操作,此时execution的当前节点为
结束事件节点
Step 7: 弹出栈顶TakeOutgoingSequenceOperation(结束节点),首先进行节点结束持久化操作,之后获取创建变量节点的可用分支,无可用分支,则构造 EndExecutionOperation,此时execution的当前节点为结束节点
Step 8: 弹出栈顶EndExecutionOperation(结束节点),执行相关结束操作