点击上方“芋道源码”,选择“设为星标”
管她前浪,还是后浪?
能浪的浪,才是好浪!
每天 10:33 更新文章,每天掉亿点点头发...
源码精品专栏
1 什么是流程引擎
流程引擎是一个底层支撑平台,是为提供流程处理而开发设计的。流程引擎和流程应用,以及应用程序的关系如下图所示。
![13d9ce1ec3280f7ce3aed74417e3427c.png](https://i-blog.csdnimg.cn/blog_migrate/ea3a8d5ca0d682b35419eb9e7e3c3b89.png)
常见的支撑场景有:Workflow、BPM、流程编排等。本次分享,主要从 BPM 流程引擎切入,介绍流程引擎的架构设计方法。
1.1 什么是流程
简单来说,流程就是一系列活动的组合。比如,用于企业办公的 OA 系统中,就存在大量的申请审批类的流程。在生产制造业,有大量的从销售端的订单,到生产制造,再到签收回款的生产销售流程。在机器学习领域,有亚马逊 AWS Sagemaker 的大数据处理、机器学习的应用。综上,流程是一个概念,在和具体实现结合时,就产生了不同的流程产品,如 DevOps、Spring Data Stream 等。
在流程实现方面,主要可以分为 2 种实现方式,一种是用代码实现,比如:用代码实现一个加班申请,那么就要自己对接 SSO 进行单点登录,通过接口拿到发起人和审批人的信息,同时保存表单数据。
另一种方式是使用流程引擎来实现,流程引擎对接应用场景所需数据,如加班申请,流程引擎对接 SSO、OU、审批人配置、权限等,实现这样一个流程,只需要关心流程配置、流程节点和流程表单即可,流程流转以及流程的数据处理,都通过流程引擎来完成。
流程引擎可以快速落地流程实现,这也是流程引擎存在的价值。
1.2 什么是引擎
一般而言,引擎是一个程序或一套系统的支持部分。常见的程序引擎有游戏引擎、搜索引擎、杀毒引擎等。引擎是脱离具体业务场景的某一类业务场景的高度抽象和封装。
比如,某 OA 公司,封装了一套审批用的 workflow,实施人员只需要配置流程和表单即可交付项目。再比如,美国某公司做了一个 AI 引擎做 NBA(Next Best Action)推荐,封装了推荐领域的常用算法,在不同的场景自动选择和组合多种算法,进行智能推荐。
1.3 流程设计器
流程设计器是流程和引擎的连接方,用户通过流程设计器,将某种 layout 和 rule 固化成某种流程,然后通过数据和数据上下文,使用流程引擎自动按照某种固化的流程进行执行。
我将目前见到的流程设计器的理论基础,分为以下三类:
自定义系;
UML 中的活动图系;
BPMN 系。
1.3.1 自定义系
用于 Sagemaker 等场景的 AWS Step Function(自定义流程节点)
![d2ab456c22a1d8089d736cd35b9fc801.png](https://i-blog.csdnimg.cn/blog_migrate/ba39e211c1bff74673951ad7f87f095a.png)
1.3.2 UML Activity Diagram
Flowportal BPM 的流程设计器
![06468d0d40e3873bfde95d12a82df857.png](https://i-blog.csdnimg.cn/blog_migrate/22c9ebaed2f6f6b834c8b48ee6b6f8d3.png)
1.3.3 BPMN 系
activiti 的流程设计器
![22bf3c909d1877f44356952896b8f936.png](https://i-blog.csdnimg.cn/blog_migrate/40090a2364006da1d29e358a1a461a6f.png)
炎黄盈动的流程设计器
![692b61b0a58ae50af636d14dd95c38d9.png](https://i-blog.csdnimg.cn/blog_migrate/c0593526dc8d9f5d19713f1d643ca750.png)
题外话:炎黄盈动的流程设计器,和 processon 中的流程设计器界面几乎一样,因为本质上是一家的。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
视频教程:https://doc.iocoder.cn/video/
2 流程引擎的应用
2.1 Workflow
工作流管理联盟 (Workflow Management Coalition,WfMC) 作为工作流管理的标准化组织而成立。
WfMC 对工作流给出定义为:工作流是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行。
![c699bb65287154578c043c8dcbff82b7.png](https://i-blog.csdnimg.cn/blog_migrate/7bcc94a1e9af74d824f43d9b20b6f8d9.png)
在 workflow 中,流程引擎主要用于支撑流程审批和数据流转,应用场景非常广泛。
国外产品(开源或商用)通常需求和操作比较简单,不会有国内的需求那么复杂。国内的产品,经历了众多客户的锤炼,功能目前都比较强大。
一般而言,workflow 使用场景最多的是 OA 产品。在 OA 办公中,包含了企业办公中的大量元素,这些元素足够形成特定的产品,比如门户系统、移动办公。在 OA 的项目落地过程中,结合行业、业务侧重点又可以形成行业解决方案和专题方案。
以下是某 OA 公司产品和解决方案。
![43632ec6f53607ced62522a6bde09e73.png](https://i-blog.csdnimg.cn/blog_migrate/f3739ac286cff79ea33d6c3d9192ce54.png)
2.2 BPM(Business Process Management)
Workflow 主要是解决审批和数据流转,而 BPM 主要是解决端到端、信息孤岛等问题而存在的。大多数用 BPM 产品的客户,都是在 BPM 基础上进行系统搭建,比如在 BPM 上面搭建 OA、CRM、HR 等系统。
BPM 的使用场景,比 Workflow 更广泛,BPM 产品中包含大量的和第三方系统交互的组件和自定义 SQL、代码组件。
比如,BPM 系统中的文件触发器,可以在海关等交互场景下,通过监控 FTP 服务器中的文件,自动触发流程实例;可以通过定时器 Timer,自动每日执行数据同步,并通过 Mail 节点将同步结果通知到相关运营成员等。
![866a0c779627d80effe8f27a5bd45aeb.png](https://i-blog.csdnimg.cn/blog_migrate/c25ce654607df0a9aeeaa65eaa11d943.png)
![460881fb8897c415d42d0707c2cf2f89.png](https://i-blog.csdnimg.cn/blog_migrate/2d31bad9f7698599f1bd27c719520231.png)
BPM 的应用,可以按照执行前、执行中和执行后来划分。
![f0975c0b3637c4ae41ef308f6c4ab8f4.png](https://i-blog.csdnimg.cn/blog_migrate/3b8f0114fdd434c3aa1e58ed3efab66b.png)
2.3 流程编排
流程编排是脱离流程业务领域的更高一层抽象,使用方可以通过流程编排系统,结合自己的业务场景进行业务定制。比如,可以将相关业务代码,封装成 function,然后通过云厂商平台的 FAAS 平台,将不同业务的 function 进行关联和调度,从而完成某项任务。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://gitee.com/zhijiantianya/yudao-cloud
视频教程:https://doc.iocoder.cn/video/
3 流程引擎的架构设计
鉴于一些朋友可能没有使用和接触过流程引擎,先介绍流程引擎的组成单元,再介绍基于某个 BPM 产品的项目是如何进行开发的。我们通过 BPM 项目开发,对流程引擎的作用有个初步的认识。
3.1 BPM 流程引擎的组成单元
组织、角色、用户、成员的组织架构托管;
流程资源文件的配置、校验、存储和执行,对不同的流程节点,流程引擎自动结合配置、数据处理其对应的业务逻辑,流程数据自动处理;
表单配置、数据绑定,表单数据的根据流程配置自动处理;
通用的数据接口;
3.1.1 组织架构的设计
![4fddee8819e7ddc393b884d0a56a1a6f.png](https://i-blog.csdnimg.cn/blog_migrate/87f3fc53647617ec76a20c25ba70cc9d.png)
3.1.2 流程设计器
流程设计器包含左侧的分组节点列表,和右侧的画布。左侧的节点可以如下进行设计。
![5d7e3da73ea650abfabd1d80c2c0e5bb.png](https://i-blog.csdnimg.cn/blog_migrate/fe543d10e38262907cbd2819c539de4f.png)
问题:对于一个 XML 或 JSON 格式的流程图,如何进行解析?
不同的节点,按照不同的业务场景,配置不同的配置项。比如,对于 Human Node 需要配置审批人,配置审批环节的展示表单,审批环节能够修改哪些字段,哪些字段的修改要进行留痕等。
3.1.3 表单设计器
![7bda03b2c910744ab364c75a5f64d1ee.png](https://i-blog.csdnimg.cn/blog_migrate/2857c6ede4491cce1032284d38b0fac8.png)
![b88090ae54c44a220669e18a53428668.png](https://i-blog.csdnimg.cn/blog_migrate/2361ed94202155d7181fa01aa55881cb.png)
这种是按照表单相关数据表,生成出一个表单,然后对表单字段进行配置和数据绑定。
![918bf41594c6a0a6f83357ea6b82b315.png](https://i-blog.csdnimg.cn/blog_migrate/df5902bf967123a8feb3adb782ce42a7.png)
![8fd9c72d3f466b13b0a2d18bd5059715.png](https://i-blog.csdnimg.cn/blog_migrate/1ec4aea9a173b8decd42f63b89022486.png)
这种是 Drag&Drop 控件,然后配置控件的属性,如绑定字段等。
![652820c24211195aab6ab62c9ab926f7.png](https://i-blog.csdnimg.cn/blog_migrate/0ab41a0adb20c0f632ca28a188a2b76e.png)
这种是 Drag&Drop 控件,无需关联数据库表字段的表单
![4a1b7ede7116def04995ad9de162ae42.png](https://i-blog.csdnimg.cn/blog_migrate/96b9bf090f73f7f8fad095bbc7189825.png)
数据表生成表单的概要流程如下图所示。
![7c293e1f4071565854e7d59e90ed4e95.png](https://i-blog.csdnimg.cn/blog_migrate/86b419579e19f3eee95ba2a828316b0f.png)
拖拽控件绑定数据表字段的概要流程如下。
![5c6aeba6064e6f2368ff1d37de113084.png](https://i-blog.csdnimg.cn/blog_migrate/f339699b738e4e87512c2b8b652495cd.png)
拖拽控件无需绑定数据表字段的概要流程。使用 NoSQL 的 Document 记录或使用 RDS 提供的 JSON 类型进行保存会比较方便。
![2d4683e75597510e81dc7b1073f0c734.png](https://i-blog.csdnimg.cn/blog_migrate/65266146c157c2d5da46ab6e579873fa.png)
3.1.4 接口设计
结合 Activity 的接口设计,如下图所示
![35940ac2633c50f160b1e7a4206584fc.png](https://i-blog.csdnimg.cn/blog_migrate/312f16ced24ee1ddc8e8c8bd98e46918.png)
一些系统在创建一个流程任务的时候,要先按照流程模板先创建一个应用示例,再关联发起人和备注,调用 RuntimeService
,执行到 StartNode,这类设计因人而异,这么做略显繁琐。
3.2 基于流程引擎的项目开发实践
3.2.1 流程项目实践流程
确定组织架构
确定流程,包括流程布局、审批人设置、权限
确定表单信息(字段、类型、数据源、校验规则)和表单样式
确定页面布局、样式、数据字段、搜索、导入、导出
报表
3.2.2 组织架构
组织架构实现,有两种方法,一种是按照维度进行数据管理,另一种是在同一棵组织架构树下进行管理。
按照集团、公司、部门、用户等不同维度,进行数据管理,比较常见,这里不做讨论。下图为按维度维护数据的示例。
![8bf677e41ffefe94d13441b211201178.png](https://i-blog.csdnimg.cn/blog_migrate/9104456993ea8631b3e021741b51b209.png)
按照同一棵组织架构树进行数据维护,界面一般显示为左树右表。大多数商业化产品,都会将此组织架构树进行内存缓存,以方便审批人查找、开窗选择 OrgUnit、Role、User、Member 等场景。Member 的引入是为了解决一人多职等场景。一般发起流程的时候,需要带出发起人拥有的 Member 列表,从而后续节点取合适的审批人。
![edcf317ad7741ad6fb90b0914fe5dd54.png](https://i-blog.csdnimg.cn/blog_migrate/824d3faea64cc86c45d8229517773c14.png)
对于组织架构而言,需要考虑,系统本身要具备 OU 存储的能力,对于没有组织架构的用户,可以直接在系统的组织架构中新建组织架构。同时,对于已有系统的客户,可以通过组织架构数据同步来进行数据自动维护。对于用 AD 域内部管控的客户来说,需要具备 AD 域身份认证的能力。对于复杂场景,比如用户是 SaaS 化等复杂场景,组织架构也需要在系统内部,支持使用 API 的方式来获取组织信息。
所以在组织架构设计的时候,要使用插件的方式来做,具体使用哪种插件,可以在配置文件中进行配置。以下为一个商业产品的组织架构操作界面示例。
![824cfc22550e0d688002045ef564d2f9.png](https://i-blog.csdnimg.cn/blog_migrate/7b62d5fe4ae1edbdc647b54da25dcd05.png)
常见的组织架构操作还有组织架构同步,比如流程系统同步微信企业号、钉钉等,这里不再展开。
3.2.3 流程设计
我们想象的流程,可能是向下面的这种简单流程。
![1b7366dd33341f7132978327f0c52d85.png](https://i-blog.csdnimg.cn/blog_migrate/85666a269cbacdbe6ffec62223bcb5e0.png)
而实际项目,碰到的流程,一般是如下图所示的情景。
![cc0a87128d9d74bdf52166b017153368.png](https://i-blog.csdnimg.cn/blog_migrate/e8006fadd9205336b660f24b75c87bc8.png)
初步看几个流程的模型文件是什么样的,先有个印象。
![cb99718a0cec3b4484ab2dc6dfddb8de.png](https://i-blog.csdnimg.cn/blog_migrate/264cbaa816332140598f534e8487d88a.png)
<?xml version="1.0" encoding="UTF-8" ?>
<definitions id="definitions"
targetNamespace="http://activiti.org/bpmn20"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn">
<process id="vacationRequest" name="Vacation request">
<startEvent id="request" activiti:initiator="employeeName">
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" type="long" value="1" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" type="string" />
</extensionElements>
</startEvent>
<sequenceFlow id="flow1" sourceRef="request" targetRef="handleRequest" />
<userTask id="handleRequest" name="Handle vacation request" >
<documentation>
${employeeName} would like to take ${numberOfDays} day(s) of vacation (Motivation: ${vacationMotivation}).
</documentation>
<extensionElements>
<activiti:formProperty id="vacationApproved" name="Do you approve this vacation" type="enum" required="true">
<activiti:value id="true" name="Approve" />
<activiti:value id="false" name="Reject" />
</activiti:formProperty>
<activiti:formProperty id="managerMotivation" name="Motivation" type="string" />
</extensionElements>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>management</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id="flow2" sourceRef="handleRequest" targetRef="requestApprovedDecision" />
<exclusiveGateway id="requestApprovedDecision" name="Request approved?" />
<sequenceFlow id="flow3" sourceRef="requestApprovedDecision" targetRef="sendApprovalMail">
<conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'true'}</conditionExpression>
</sequenceFlow>
<task id="sendApprovalMail" name="Send confirmation e-mail" />
<sequenceFlow id="flow4" sourceRef="sendApprovalMail" targetRef="theEnd1" />
<endEvent id="theEnd1" />
<sequenceFlow id="flow5" sourceRef="requestApprovedDecision" targetRef="adjustVacationRequestTask">
<conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'false'}</conditionExpression>
</sequenceFlow>
<userTask id="adjustVacationRequestTask" name="Adjust vacation request">
<documentation>
Your manager has disapproved your vacation request for ${numberOfDays} days.
Reason: ${managerMotivation}
</documentation>
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" value="${numberOfDays}" type="long" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" value="${startDate}" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" value="${vacationMotivation}" type="string" />
<activiti:formProperty id="resendRequest" name="Resend vacation request to manager?" type="enum" required="true">
<activiti:value id="true" name="Yes" />
<activiti:value id="false" name="No" />
</activiti:formProperty>
</extensionElements>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>${employeeName}</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
</userTask>
<sequenceFlow id="flow6" sourceRef="adjustVacationRequestTask" targetRef="resendRequestDecision" />
<exclusiveGateway id="resendRequestDecision" name="Resend request?" />
<sequenceFlow id="flow7" sourceRef="resendRequestDecision" targetRef="handleRequest">
<conditionExpression xsi:type="tFormalExpression">${resendRequest == 'true'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow8" sourceRef="resendRequestDecision" targetRef="theEnd2">
<conditionExpression xsi:type="tFormalExpression">${resendRequest == 'false'}</conditionExpression>
</sequenceFlow>
<endEvent id="theEnd2" />
</process>
</definitions>
一个屏幕截图都截不完的流程,如果用代码去实现整个流程,其工作量和效率,可想而知。而实际做项目,使用基于流程引擎的产品来做项目的时候,只需要确定节点、节点配置、数据配置和权限即可。
问题:一般流程,都带有邮件通知的节点,如何实现邮件通知节点?请考虑以下情景。
流程流转和执行的时候,会遇到各种情况的错误,比如找不到审批人等,此时流程引擎要对数据做 rollback,而邮件通知节点的业务逻辑已经执行过了。
权限方面,对于流程资源,哪些部门可以申请,哪些角色不可申请,都应该做流程控制。而在流程执行过程中,流程数据、不是路程的相关人也都不应该看到流程,处理过流程的审批人,不可以再对流程进行处理等,都是权限方面要考虑的问题。
3.2.4 表单设计
如下图所示的表单,可以分析以下,一个流程表单有多个主表信息和多个子表信息。一般而言,如果是通过流程引擎做非流程的数据处理,子表通过主表 ID 来做关联,如果通过流程引擎做流程的数据处理,子表和主表通过 TaskId 来做关联。以下为示例。
![f9c2b85d1efa15c6f07c97252d778fc0.png](https://i-blog.csdnimg.cn/blog_migrate/0da25d4fda38d29ab6c8228099be7e7a.png)
流程系统需要表单设计器,一个流程的不同节点可以挂接不同的表单,以方便不同角色的人关注不同维度的流程信息
3.2.5 页面设计
一般而言,对于流程的发起、审批、历史记录等,都是通用的系统界面。而一些业务场景,需要单独做列表界面,以方便使用。对于已有门户系统的客户,需要融合其界面样式。以下为曾经做过的项目示例。
![9d15b9de412e6d1ec2b77607d5d80a13.png](https://i-blog.csdnimg.cn/blog_migrate/403d8515289418e119da60ae66eb37d2.png)
![f989209555e2b28e80e9a3b3f794c05b.png](https://i-blog.csdnimg.cn/blog_migrate/442a38128ef226dc370912bd95da3930.png)
3.2.6 报表
由于不是所有客户都有报表系统,所以流程系统需要具备一个基本的报表功能。下图为示例。
![9289bd4a8f8adf2e28d2271fbb80d662.png](https://i-blog.csdnimg.cn/blog_migrate/c17a9467837dcff2998be80b33964469.png)
有报表系统的客户,可以使用其商业版报表系统,获取(直接取、数仓)数据进行展示。常见的报表系统有 FineReport、Tableau、PowerBI 等。
3.3 BPM 流程引擎架构设计
3.3.1 流程引擎的架构设计
![6df180f24d53b9d24519beea50ea9ec8.png](https://i-blog.csdnimg.cn/blog_migrate/90502085d607d727eef5170ff105376a.png)
3.3.2 发起流程
![236b92eafbf68ea79f38f61d3870e0ec.png](https://i-blog.csdnimg.cn/blog_migrate/ae8d4e880575c1d88f8cc6f423db6739.png)
流程引擎处理过程
![6b5a42087ac80594eb0c79f1848eb57a.png](https://i-blog.csdnimg.cn/blog_migrate/6da845e1e51188498797a5d667cc7a5c.png)
执行节点处理过程
![bf762448341f440b85877477ee10dac7.png](https://i-blog.csdnimg.cn/blog_migrate/2b7d78c4a4a0d72a778c1d47b119948c.png)
问题:在流程引擎处理过程中,如果一个节点有多条连线,如何寻找 FromNodeId 是某个 Node 的连线?
人工处理时,指定连线 text
3.4 流程引擎架构设计
![d7eff2e5f98a4be4c3fc03a3c7b99b29.png](https://i-blog.csdnimg.cn/blog_migrate/b2be3b1cb170f9a50b063e8a2d4c308a.png)
3.4.1 业务识别
识别业务场景中的配置项,使用集合或分组的方式,让业务可配置
支撑业务流程过程的可配置化
支撑业务场景中的数据,自动处理
3.4.2 流程引擎的实现
资源相关服务,资源加载,资源保存,资源加密等
配置项相关服务
PVM 虚拟机的实现,即通过某个节点(发起时为开始节点)作为初始节点,按照某个连线的 action 进行节点的自动执行的虚拟机
数据配置、数据权限
流程数据和业务数据的自动处理
4 商业机会
Business Process Analysis (BPA) 流程分析,帮助企业进行流程调整和优化
Process Assets Library(PAL)流程资产库,对企业流程进行知识化沉淀,将制度和流程落地做绑定,让审批人知晓流程中对应的职责
Process Simulate 流程模拟,自动化测试
Process Forecast 流程预测
低代码平台
更广泛的机会,在于业务领域 + 流程引擎,比如:DevOps、RPA、应用与服务编排、数据编排、FaaS 编排等。
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)