工作中,基于实际情况的需要,自研了一款工作流引擎,期间有不少收获,愿与同学们分享,听我娓娓道来…
一、什么是工作流引擎
简而言之,工作流引擎就是驱动工作流执行的一套代码。
至于什么是工作流、为什么要有工作流、工作流的应用场景,同学们可以看一看网上的资料,在此处不在展开。
二、为什么要重复造轮子
开源的工作流引擎很多,比如 activiti、flowable、Camunda 等,那么,为什么没有选它们呢?基于以下几点考虑:
- 最重要的,满足不了业务需求,一些特殊的场景无法实现。
- 有些需求实现起来比较绕,更有甚者,需要直接修改引擎数据库,这对于引擎的稳定运行带来了巨大的隐患,也对以后引擎的版本升级制造了一些困难。
- 资料、代码量、API繁多,学习成本较高,维护性较差。 经过分析与评估,我们的业务场景需要的BPMN元素较少,开发实现的代价不大。
因此,重复造了轮子,其实,还有一个更深层次的战略上的考虑,即:作为科技公司,我们一定要有我们自己的核心底层技术!这样,才能不受制于人(参考最近的芯片问题)。
三、怎么造的轮子
对于一次学习型分享来讲,过程比结果更重要,那些只说结果,不细说过程甚至不说的分享,我认为是秀肌肉,而不是真正意义上的分享。因此,接下来,本文将重点描述造轮子的主要过程。
一个成熟的工作流引擎的构建是很复杂的,如何应对这种复杂性呢?一般来讲,有以下三种方法
- 确定性交付:弄清楚需求是什么,验收标准是什么,最好能够写出测试用例,这一步是为了明确目标。
- 迭代式开发:先从小的问题集的解决开始,逐步过渡到解决大的问题集上来,罗马不是一天建成的,人也不是一天就能成熟的,是需要个过程的。
- 分而治之:把大的问题拆成小的问题,小问题的解决会推动大问题的解决(这个思想适用场景比较多,同学们可以用心体会和理解哈)。
如果按照上述方法,一步一步的详细展开,那么可能需要一本书。为了缩减篇幅而又不失干货,本文会描述重点几个迭代,进而阐述轻量级工作流引擎的设计与主要实现。
那么,轻量级又是指什么呢?这里,主要是指以下几点
- 少依赖:代码的java实现上,除了jdk8以外,不依赖与其他第三方jar包,从而可以更好的减少依赖带来的问题。
- 内核化:设计上,采用了微内核架构模式,内核小巧,实用,同时提供了一定的扩展性。从而可以更好地理解与应用本引擎。
- 轻规范:并没有完全实现BPMN规范,也没有完全按照BPMN规范进行设计,而只是参考了该规范,且只实现以一小部分必须实现的元素。从而降低了学习成本,可以按照需求自由发挥。
- 工具化:代码上,只是一个工具(UTIL),不是一个应用程序。从而你可以简单的运行它,扩展你自己的数据层、节点层,更加方便的集成到其他应用中去。
好,废话说完了,开始第一个迭代…
四、Hello ProcessEngine
按照国际惯例,第一个迭代用来实现 hello world 。
1、需求
作为一个流程管理员,我希望流程引擎可以运行如下图所示的流程,以便我能够配置流程来打印不同的字符串。

2、分析
- 第一个流程,可以打印Hello ProcessEngine,第二个流程可以打印ProcessEngine Hello,这两个流程的区别是只有顺序不同,蓝色的节点与红色的节点的本身功能没有发生变化
- 蓝色的节点与红色的节点都是节点,它们的功能是不一样的,即:红色的节点打印Hello,蓝色的节点打印ProcessEngine
- 开始与结束节点是两个特殊的节点,一个开始流程,一个结束流程
- 节点与节点之间是通过线来连接的,一个节点执行完毕后,是通过箭头来确定下一个要执行的节点
- 需要一种表示流程的方式,或是XML、或是JSON、或是其他,而不是图片
3、设计
流程的表示
相较于JSON,XML的语义更丰富,可以表达更多的信息,因此这里使用XML来对流程进行表示,如下所示
<definitions>
<process id="process_1" name="hello">
<startEvent id="startEvent_1">
<outgoing>flow_1</outgoing>
</startEvent>
<sequenceFlow id="flow_1" sourceRef="startEvent_1" targetRef="printHello_1" />
<printHello id="printHello_1" name="hello">
<incoming>flow_1</incoming>
<outgoing>flow_2</outgoing>
</printHello>
<sequenceFlow id="flow_2" sourceRef="printHello_1" targetRef="printProcessEngine_1" />
<printProcessEngine id="printProcessEngine_1" name="processEngine">
<incoming>flow_2</incoming>
<outgoing>flow_3</outgoing>
</printProcessEngine>
<sequenceFlow id="flow_3" sourceRef="printProcessEngine_1" targetRef="endEvent_1"/>
<endEvent id="endEvent_1">
<incoming>flow_3</incoming>
</endEvent>
</process>
</definitions>
- process表示一个流程
- startEvent表示开始节点,endEvent表示结束节点
- printHello表示打印hello节点,就是需求中的蓝色节点
- processEngine表示打印processEngine节点,就是需求中的红色节点
- sequenceFlow表示连线,从sourceRef开始,指向targetRef,例如:flow_3,表示一
- 从printProcessEngine_1到endEvent_1的连线。
节点的表示
outgoing表示出边,即节点执行完毕后,应该从那个边出去。
incoming表示入边,即从哪个边进入到本节点。
一个节点只有outgoing而没有incoming,如:startEvent,也可以 只有入边而没有出边,如:endEvent,也可以既有入边也有出边,如:printHello、processEngine。
流程引擎的逻辑
基于上述XML,流程引擎的运行逻辑如下
- List item
- 找到开始节点(startEvent)
- 找到startEvent的outgoing边(sequenceFlow)
- 找到该边(sequenceFlow)指向的节点(targetRef)
- 执行节点自身的逻辑
- 找到该节点的outgoing边(sequenceFlow)
- 重复3-5,直到遇到结束节点(endEvent),流程结束
4、实现
首先要进行数据结构的设计,即:要把问题域中的信息映射到计算机中的数据。
可以看到,一个流程(PeProcess)由多个节点(PeNode)与边(PeEdge)组成,节点有出边(out)、入边(in),边有流入节点(from)、流出节点(to)。
具体的定义如下:
public class PeProcess {
public String id;
public PeNode start;
public PeProcess(String id, PeNode start) {
this.id = id;
this.start = start;
}
}
public class PeEdge {
private String id;
public PeNode from;
public PeNode to;
public PeEdge(String id) {
this.id = id;
}
}
public class PeNode {
private String id;
public String type;
public PeEdge in;
public PeEdge out;
public PeNode(String id) {
this.id=id;
}
}
PS : 为了表述主要思想,在代码上比较“奔放自由”,生产中不可直接复制粘贴!
接下来,构建流程图,代码如下:
public class XmlPeProcessBuilder {
private String xmlStr;
private final Map<String, PeNode> id2PeNode = new HashMap<>();
private final Map<String, PeEdge> id2PeEdge = new HashMap<>();
public XmlPeProcessBuilder(String xmlStr) {
this.xmlStr = xmlStr;
}
public PeProcess build() throws Exception {
//strToNode : 把一段xml转换为org.w3c.dom.Node
Node definations = XmlUtil.strToNode(xmlStr);
//childByName : 找到definations子节点中

本文介绍了从零开始构建一个轻量级工作流引擎的过程,包括实现HelloWorld流程,设计并处理简单审批流程,以及在审批流程中引入分支判断。通过逐步迭代,展示了如何通过XML定义流程,实现节点的注册与调度,以及数据在节点间的传递。最终,工作流引擎具备了处理复杂审批逻辑的能力。
最低0.47元/天 解锁文章
2252





