如何优雅的设计工作流引擎(荣耀典藏版)_微型workflow-程序员宅基地

技术标签: java  mybatis  架构设计  # java基础  开发语言  

目录

前言

一、业务应用场景

二、工作流介绍

2.1 定义

2.2 工作流参考模型

2.3 工作流引擎特性

2.3 工作流引擎特性

2.5 工作流引擎和状态机的差异

三、开源工作流引擎

3.1.Activiti

3.2.Flowable

3.3.Camunda

3.4.jBPM

3.5.osworkflow

四、工作流引擎自研设计

4.1 使用开源工作流引擎的问题

4.2 自研引擎核心设计思路

4.2.1 引擎核心模块

4.3 具体实践

4.3.1引擎核心服务

 4.3.2流程定义服务

4.3.3.流程实例服务

4.3.4.流程任务节点服务

4.4 思考和扩展

五、总结


前言

大家好,我是程序缘--幻羽,我又来了!!

什么是工作流引擎(Workflow Engine )

例如开发一个系统,最关键的部分不是系统的界面,也不是和数据库之间的信息交换,而是如何根据业务逻辑开发出符合实际需要的程序逻辑并确保其稳定性、易维护性(模块化和结构化)和弹性(容易根据实际业务逻辑的变化作出程序上的变动,例如决策权的改变、组织结构的变动和由于业务方向的变化产生的全新业务逻辑等等)。 Workflow 引擎解决的就是这个问题:如果应用程序缺乏强大的逻辑层,势必变得容易出错(信息的路由错误、死循环等等)。

就好比一辆汽车,外表做得再漂亮,如果发动机有问题就只是一个摆设。应用系统的弹性就好比引擎转速方面的性能,加速到100 公里需要1 个小时(业务流程发生变动需要进行半年的程序修改)还能叫好车吗?引擎动不动就熄火(程序因为逻辑的问题陷入死循环)的车还敢开吗?

服务架构

面向服务的体系结构,是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。工作流引擎使得构建在各种这样的系统中的服务,可以以一种统一和通用的方式进行交互。

今天和大家一起学习如何优雅的设计工作流!!!!

一、业务应用场景

营销自动化平台可以支持不同用户生命周期的活动旅程策略配置 ,根据用户触发的不同活动行为,进行差异化的营销触达方案。同时各种类型活动的具体执行过程中也有不同的业务处理流程(比如审批流程和业务流转)。业务流程复杂多样,需求变更频繁,项目开发过程中会有以下痛点:

  1. 项目交付周期长: 一个完整的业务流程需要从头开始按版本迭代,开发时间长,成本高。

  2. 功能重复开发测试: 业务之间会掺杂着很多共性的流程,导致大量重复性开发测试工作,效率低。

  3. 维护成本高: 随着项目业务的逐步发展,业务流程逐步积累,可维护性下降,系统改动牵一发而动全身。

如何将业务逻辑从控制流中剥离出来,让产研人员更聚焦于业务的实现是需要重点解决的问题。而传统OA领域使用的是久经考验的业务流程管理解决方案 —— 工作流(Workflow) 。工作流是一套工业级的解决方案,由工作流管理联盟(WfMC)制定了一系列的标准。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

二、工作流介绍

2.1 定义

工作流(Workflow) —— 对工作流程及其各操作步骤之间业务规则的抽象,将流程中的工作组织逻辑和规则进行建模,交由计算机进行自动处理。

工作流的本质思想 是:通过预定义的工作流程模板,对现实活动进行实例化的过程 。简单说就是通过预设的格式或者可视化配置好流程的模板(比如一种分享活动的运行流程模板),使用时通过该模板构造出一个流程实例对象,通过实例对象完成活动运行跟踪和回溯。

2.2 工作流参考模型

WfMC工作流管理联盟为工作流制定了参考模型,其核心就是中间的工作流引擎,工作流引擎提供流程定义工具(接口1)、给使用者提供信息查询(接口2)、调用外部应用(接口3)、整合其他工作流(接口4)和监控管理(接口5)的能力。对于大多数工作流产品而言,重点关注的是接口1和接口2的实现。

2.3 工作流引擎特性

  1. 流程可视化

    提供可视化的流程搭建,流程视图查看能力,以及实时观测任务运行能力。

  2. 业务可编排复用

    将公共业务进行组件化,可以支持任务的自由编排,自由搭建出适合的业务的不同流程。

  3. 业务和控制分离

    将流程的控制(如流转、判断、循环、重试等)的任务交由工作流负责,让使用者聚焦于核心业务逻辑。

2.3 工作流引擎特性

对于工作流的类型没有专门的标准,按照流程任务节点特性可以分为:

  • 顺序工作流

顺序工作流的运行方式类似一种特定的流程图,上一个流程任务完成后依次进入下一个流程任务,过程不可逆。

  • 状态机工作流

状态机工作流侧重关注的是流程任务的状态,驱使任务状态发生变化的因素一般为外部事件,即事件驱动的方式,驱使任务节点从一个状态运行到另外一个状态,节点间可逆。

  • 规则驱动工作流

侧重于节点的运转规则,基于业务规则进行工作流程的执行,在处理具有明确目标但“规则”或规范级别不同的各种项目时,规则驱动的工作流非常有用。

可以看到不同类型的工作流不是完全割裂的,状态机工作流中也可以结合着条件和规则进行操作节点转换的过程。在软件开发中,一般会考虑结合状态机和规则驱动的工作流。

2.5 工作流引擎和状态机的差异

在之前的文章里面,我们有对状态机和工作流引擎 做过一次简单的对比 ,事实上,两者之间并不是一个完全对等的概念:

  1. 状态机 是系统状态以及这些状态之间转移和动作等行为的数学计算模型,

    工作流 是对整体工作流程及其各操作步骤之间业务逻辑和规则的抽象建模。

  2. 状态机 模式是事件驱动型,大多通过外部事件触发状态的自动流转;

    工作流引擎 更侧重于描述预定义流程任务完成之后的自动流转,可预测性会更强。

  3. 从适用场景的复杂性上看,

直接使用状态机 的方式可以清晰地描绘出所有可能的状态以及导致转换的事件,适用于解决单维度、复杂度不高的业务问题,发挥灵活轻便的特点;

工作流引擎 则更适合复杂的业务流程管理,解决如大型CRM复杂度更高的流程自动化问题,聚焦于改善整体业务流程的效率。

  1. 工作流引擎 是可以在状态机的结构模型基础上进行构建,事实上很多开源的工作流引擎也都是基于状态机的实现方式。

了解了工作流的基本特点和使用场景之后,我们来看一下比较流行的开源工作流引擎。

三、开源工作流引擎

开源框架对比:

经过对比,camunda 在功能方面比 flowable、activiti 流程引擎强大,性能和稳定性更突出。在开源流程引擎选型方面,camunda 是很好的方案之一。

3.1.Activiti

Activiti 由 Alfresco 公司开发,目前最高版本为 Activiti cloud 7.1.0。其中 activiti5 和 activiti6 的核心 leader 是 Tijs Rademakers,由于团队内部分歧,2017 年 Tijs Rademakers 离开团队,创建了后来的 Flowable。activiti6 以及 activiti5 代码则交接给 Salaboy 团队维护,activiti6 以及 activiti5 的代码官方已经暂停维护。往后 Salaboy 团队开发了 activiti7 框架,activiti7 内核使用的还是 activiti6,并没有为引擎注入更多的新特性,只是在 Activiti 之外的上层封装了一些应用。直到 Activiti cloud 7.1.0 版本,Activiti cloud 将系统拆分为 Runtime Bundle、Audit Service、Query Service、Cloud Connectors、Application Service、Notification Service。这些工作的主要目的其实就是为了上云,减少对 Activiti 依赖的耦合,需要使用 Activiti 的系统只需要通过调用 http 接口的方式来实现工作流能力的整合,将工作流业务托管上云。

3.2.Flowable

Flowable 是基于 activiti6 衍生出来的版本,目前最新版本是 v6.7.0。开发团队是从 Activiti 中分裂出来的,修复了一众 activiti6 的 bug,并在其基础上实现了 DMN 支持,BPEL 支持等。相对开源版,其商业版的功能会更强大。Flowable 是一个使用 Java 编写的轻量级业务流程引擎,使用 Apache V2 license 协议开源。2016 年 10 月,Activiti 工作流引擎的主要开发者离开 Alfresco 公司并在 Activiti 分支基础上开启了 Flowable 开源项目。Flowable 项目中包括 BPMN(Business Process Model and Notation)引擎、CMMN(Case Management Model and Notation)引擎、DMN(Decision Model and Notation)引擎和表单引擎(Form Engine)等模块。

3.3.Camunda

Camunda 基于 activiti5,所以其保留了 PVM,最新版本 Camunda7.17,开发团队也是从 activiti 中分裂出来的,发展轨迹与 Flowable 相似。通过压力测试验证 Camunda BPMN 引擎性能和稳定性更好。功能比较完善,除了 BPMN,Camunda 还支持 CMMN(案例管理)和 DMN(决策自动化)。Camunda 不仅带有引擎,还带有非常强大的工具[6],用于建模、任务管理、操作监控和用户管理。

3.4.jBPM

jBPM 由 JBoss 公司开发,目前最高版本 7.61.0.Final,不过从 jBPM5 开始已经跟之前不是同一个产品了,jBPM5 的代码基础不是 jBPM4,而是从 Drools Flow 重新开始,基于 Drools Flow 技术在国内市场上用的很少,jBPM4 诞生的比较早,后来 jBPM4 创建者 Tom Baeyens 离开 JBoss 后,加入 Alfresco 后很快推出了新的基于 jBPM4 的开源工作流系统 Activiti,另外 jBPM 以 Hibernate 作为数据持久化 ORM,而 Hibernate 也已不是主流技术。

3.5.osworkflow

osworkflow 是一个轻量化的流程引擎,基于状态机机制,数据库表很少,osworkflow 提供的工作流构成元素有:步骤(step)、条件(conditions)、循环(loops)、分支(spilts)、合并(joins)等,但不支持会签、跳转、退回、加签等这些操作,需要自己扩展开发,有一定难度。如果流程比较简单,osworkflow 是很好的选择。

四、工作流引擎自研设计

4.1 使用开源工作流引擎的问题

  1. 开源工作流最大的优势是可以借助开源的资源,开箱即用,功能全面,但是与之带来的是附带的配置和表数量比较多的维护问题。以Activiti为例,使用Activiti7.0版本至少要引入二十多张表,虽然说看似是无侵入的方式,但是系统演进和维护过程中有一定的成本。特别是业务流程实例很多的时候,开发人员需要对表逻辑有更深的把控。

  2. 由于业务的客观独特性,作为业务流程组件,一般都需要根据自身业务进行二次开发适配。比如需要根据自身组织架构,进行流程节点用户角色权限的管控;将自身的业务能力插件化,加入工作流程配置中,进行拦截回调等。

4.2 自研引擎核心设计思路

4.2.1 引擎核心模块

回归工作流的本质, 工作流是通过预定义的流程模板,对现实活动进行实例化的过程。一个基本的工作流引擎主要包括三大核心部分:

  • 流程模板创建

    根据业务规则和逻辑,创建流程模板,设置每一个节点的操作和变更路径。基于模板创建,可以延伸出流程设计器、插件式节点,多样化的模板文件格式、模板持久化等。

  • 流程实例发布

    根据流程模板,创建一个流程实例,流程模板和流程实例的关系类似类和对象的关系。比如说工单系统管理员定义好一个审批流模板(流程模板),用户点击创建一个工单(流程实例)。基于流程实例发布,又可以延伸出实例实时观测,节点变迁记录回溯,实例状态持久化,失败重试,事务控制等。

  • 任务流程执行

    创建好流程实例之后,流程实例只需要按照流程模板的定义独立执行各自实例的任务,不同的实例之间互不影响,完成各自实例的生命周期。

 4.2.2 引擎核心设计

  1.  应用容器启动时,加载流程引擎环境配置,包括解析器构造,流程引擎上下文,流程定义文件路径等。
  2. 读取定好的流程定义文件,进行流程节点解析,构建好执行上下文,将流程节点放到内存缓存中。
  3. 业务侧进行流程创建,启动一个新的流程实例,同时将业务流程和流程实例进行绑定。
  4. 运行流程实例各个节点,将每个流程节点进行持久化保存。

4.3 具体实践

4.3.1引擎核心服务

引擎操作的主要对外接口,包括启动流程实例,和获取相关流程定义模板,流程实例,流程节点的服务。

public interface FlowEngine {
 
    /**
     * 根据流程定义key,参数列表启动流程实例
     *
     */
    FlowInstance startInstance(String processDefKey, Map<String, Object> args);
 
    /**
     * 根据流程定义主键ID,参数列表执行流程任务(推动流程自动流转)
     * 统一事务控制
     */
    void execInstance(Long instanceId, Map<String, Object> args) throws FlowAuthorityException;
 
     /**
     * 获取流程定义process服务
     *
     */
    ProcessService process();
 
    /**
     * 获取流程实例服务
     *
     */
    InstanceService instance();
 
    /**
     * 获取任务节点服务
     *
     */
    TaskService task();
}

 4.3.2流程定义服务

主要是针对流程定义模板的创建和发布,可以根据具体的实现类来支持不同的创建方式。

public interface ProcessService {  
   /**
     * 创建流程定义模板
     *
     */
    void create(String definition);
 
   /**
     * 发布流程定义模板
     *
     */
    void deploy(String fileName);
 
    /**
     * 获取流程key对应的流程定义
     */
    FlowProcess getProcessByDefKey(String processDefKey);
}

4.3.3.流程实例服务

提供流程实例创建持久化和流程实例执行的入口。

public interface InstanceService {
    /**
     * 创建流程实例
     *
     */
    FlowInstance createInstance(FlowProcess process, Map<String, Object> args);
 
    /**
     * 执行流程实例
     *
     * @param instanceId 流程实例id
     */
    void exec(Long instanceId);
 
    /**
     * 根据id获取流程实例
     *
     * @param instanceId
     * @return
     */
    FlowInstance getById(Long instanceId);
}

4.3.4.流程任务节点服务

提供流程节点具体每个任务的创建和查询。

public interface TaskService {
 
    /**
     * 根据任务模型、执行对象创建新的任务
     *
     */
    FlowTask createTask(TaskModel taskModel, Execution execution);
 
    /**
     * 完成任务
     *
     */
    FlowTask complete(Long taskId,  Map<String, Object> args);
 
    /**
     * 获取流程实例中正在进行的任务
     *
     */
    FlowTask getActiveTask(Long instanceId);
 
    /**
     * 获取流程实例上一个已完成的任务
     *
     */
    FlowHistTask getLastDoneTask(Long instanceId);
}

其中核心的方法 就是

FlowEngine#startInstanceByKey,启动流程实例。基于流程定义,创建一个流程实例对象。

FlowEngine#execInstance,执行流程实例任务,通过传入的上下文参数(操作人,操作变量等),按照流程定义的节点任务,推进流程实例的自动流转。

4.4 思考和扩展

  1. 流程定义解析性能。

    由于目前设计是在应用启动时对所有的流程定义文件进行加载和解析,流程定义文件过多时会影响应用启动速度,可以通过多线程解析和懒加载(使用时解析)两种方式进行优化。

  2. 流程定义版本兼容性。

    由于业务流程不是一成不变的,在项目发展过程中会不断进行迭代,需要对前面不同的流程进行兼容。

  3. 流程节点插件化和编排能力 。

    将基础服务进行提取公用,以支持绘制不同流程的插件化和编排能力。

  4. 流程执行监控能力。

    对流程任务节点执行情况进行埋点上报,系统自动进行监测告警。

五、总结

工作流的本质思想是通过预定义的工作流程模板,对现实活动进行实例化的过程。一般需要具备流程可视化、业务可编排复用、 业务和控制分离的基本能力。一般常见的工作流分为顺序工作流、状态机工作流和规则驱动工作流,开源工作流框架中最常见的是状态机工作流,利用事件驱动的方式,驱使流程运转。

同时简单介绍了业界比较流行的几种开源工作流引擎的特点,结合开源工作流引擎的特点的问题,并且针对多样化和迭代频繁的业务流程, 以工作流的本质思想为出发点,我们自研了一套轻量级的工作流引擎,分享了在实践过程中的设计思路和总结思考。

 只有当你开始,你才会到达你的理想和目的地,只有当你努力,
你才会获得辉煌的成功,只有当你播种,你才会有所收获。只有追求,
才能尝到成功的味道,坚持在昨天叫立足,坚持在今天叫进取,坚持在明天叫成功。欢迎所有小伙伴们点赞+收藏!!!

都看到这里了,就点个 吧。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_48321993/article/details/126031222

智能推荐

【Netty】ByteToMessageDecoder源码解析_netty 基于bytetomessagedecoder自定义起始字节和结尾字节-程序员宅基地

文章浏览阅读717次。本节我主要分析一下server端解析报文的一个过程,client当然也很重要,尤其在建立TCP连接和关闭连接需要严格控制,否则服务端会发现大量的CLOSE_WAIT(被动关闭连接),甚至大量TIME_WAIT(主动关闭连接),关于这个处理之前的文章有讲解。读了ByteToMessageDecoder的部分源码,以及它的实现JsonObjectDecoder,那么如果我们自己实现一个Decoder该如何实现,这里提供三个思路给大家,有时间再补充代码。累加器的作用是解决tcp数据包中出现半包和粘包问题。_netty 基于bytetomessagedecoder自定义起始字节和结尾字节

结构光系统标定(一)标准结构光系统_结构光标定-程序员宅基地

文章浏览阅读5.7k次,点赞12次,收藏33次。从最基本的标准结构光系统开始,尽可能详细地推导结构光系统标定的经典模型_结构光标定

java方法名是什么_什么是java的方法-程序员宅基地

文章浏览阅读3.3k次。java的方法是一段可以被重复调用的代码块。方法的声明: (推荐学习:java课程)public static 方法返回值 方法名([参数类型 变量……]){方法代码体;return 返回值;}方法的定义包括两部分:方法头和方法体。方法头可以由方法的类型,名称和名称之后的括号以及有参数的列表组成。方法体由一对括号和括号之间的内容组成。内容包括java语句及变量的声明(指局部变量)。当..._方法名是什么

如何安装Ctags 和 Taglist_tlist_exist_onlywindow-程序员宅基地

文章浏览阅读509次。参考链接 :http://blog.sina.com.cn/s/blog_684355870100jqz3.htmlCtags 下载链接:Taglist 下载链接:_tlist_exist_onlywindow

MATLAB神经网络学习_matlab神经网络进行多轮学习-程序员宅基地

文章浏览阅读8.6k次。由于做研究需要,学习了一下matlab的知识。在学习过程当中也出现过问题,也学会一些办法来解决这些问题。在这里做一下笔记,来记录matlab神经网络学习过程。以下内容中还有很多是从网上借鉴而来,权当学习。1.什么是神经网络比较粗浅的解释是,我们把输入信号当做matlab中需要输入的数据,将这些数据输入到神经网路后,这些数据都会乘以个数,即权值w,得出的结果再与阈值b相加后求和得到u,为了能_matlab神经网络进行多轮学习

身份验证错误,指定的句柄无效_发生身份验证错误,指定的句柄无效-程序员宅基地

文章浏览阅读2.8k次。身份验证错误,指定的句柄无效猜测可能是因为以前保存的凭据出错,并且新输入的密码没能正确保存的缘故。试试看这样做:1,打开开始菜单,点击右上角的用户帐户图片2,点击左侧的“管理您的凭据”链接3,在“Windows凭据”类别下,应该会列出一些内容,找到并删除“TERMSRV/xxx”,其中“xxx”是目标机器的机器名或IP地址4,重新尝试连接转载:解决方法..._发生身份验证错误,指定的句柄无效

随便推点

linear-gradient的角度与百分比_lineargradient 角度-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏5次。目录一、角度二、百分比三、测试代码一、角度垂直向上方向是0度,顺时针方向选中与垂直向上形成的夹角是角度。注意,标准的语法是不支持起使方向,例如: background: linear-gradient(top, red, blue);如果要使用起使角度,家私用前缀:background: -ms-linear-gradient(top, red, blue);background: -webkit-linear-gradient(top, red, blue);background: -o_lineargradient 角度

【PostgreSQL】PostgreSQL查表的全局索引、普通索引_pgsql表索引查看-程序员宅基地

文章浏览阅读812次,点赞12次,收藏7次。【代码】【PostgreSQL】PostgreSQL查表的全局索引、普通索引。_pgsql表索引查看

人工智能与金属材料:未来的强度-程序员宅基地

文章浏览阅读827次,点赞8次,收藏12次。1.背景介绍人工智能(AI)和金属材料是两个庞大的领域,它们在现代科技中扮演着越来越重要的角色。随着计算能力的不断提高和数据处理技术的不断发展,人工智能已经成功地应用于许多领域,包括自动驾驶、语音助手、图像识别等。而金属材料则是工程材料领域的重要一环,它们的性能和可靠性对于现代工业和技术的发展具有重要意义。然而,在这两个领域之间,我们可以发现一种有趣的联系:人工智能可以帮助我们更好地理解和...

imei服务器清除id_苹果绕过ID解锁_苹果手机怎么用序列号解id解锁-程序员宅基地

文章浏览阅读1.5k次,点赞43次,收藏41次。首先搞明白什么是苹果激活锁有叫id锁,一定要把他和屏幕锁区别开来,屏幕锁就是让输入四位,六位,或者更多符号的,密码锁,这个经常使用智能手机的用户都只能,苹果的手机和安卓的有很大不同,安卓机有设置图形锁,苹果的没有这个图形锁,激活id锁很多时候是屏幕锁忘记了,刷机以后出现的的,很多人设置了屏幕锁忘记了,输入多次出现iPhone 已停用,需要连接iTunes ,这个情况下就需要连接电脑上用iTunes 刷机才可以._苹果手机怎么用序列号解id解锁

Error building SqlSession.一招解决-程序员宅基地

文章浏览阅读7.2k次,点赞9次,收藏30次。解决方法:把所有配置文件的编码格式由UTF-8全部改为UTF8 ,喜欢技术的,一起进群交流学习吧!!!_error building sqlsession.

IOS UDID 6种方法在线获取_udid获取-程序员宅基地

文章浏览阅读5k次。(5)安装成功后自动跳转工具箱UDID page,显示UDID number,可发送至email。(2)打开iTunes(现在中文名叫"音乐"),点击顶部那一栏的信息,可以切换看到不同的信息。下的iPhone,点击顶部那一栏的序列号信息,可以切换看到不同的信息,找到UDID。(4)提示正在尝试下载一个配置描述文件(允许),设置里安装蒲公英描述文件。(3)选中自己的手机,就能看到信息,"Identifier"= UDID。(2)ios手机右上角下拉,选择扫一扫,扫描二维码。(1)usb,手机连接电脑后。_udid获取