专栏名称: Java基基
一个苦练基本功的 Java 公众号,所以取名 Java 基基
目录
相关文章推荐
混沌学园  ·  Star VC创始人任泉混沌开讲:创不创业? ·  昨天  
51好读  ›  专栏  ›  Java基基

流程引擎的架构设计方案全解

Java基基  · 公众号  ·  · 2025-02-20 11:55

正文

👉 这是一个或许对你有用 的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入 芋道快速开发平台 知识星球。 下面是星球提供的部分资料:

👉 这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本

来源:my.oschina.net/u/
4090830/blog/5584471


1 什么是流程引擎

流程引擎是一个底层支撑平台,是为提供流程处理而开发设计的。流程引擎和流程应用,以及应用程序的关系如下图所示。

常见的支撑场景有: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 固化成某种流程,然后通过数据和数据上下文,使用流程引擎自动按照某种固化的流程进行执行。

我将目前见到的流程设计器的理论基础,分为以下三类:

  1. 自定义系;
  2. UML 中的活动图系;
  3. BPMN 系。
1.3.1 自定义系

用于 Sagemaker 等场景的 AWS Step Function(自定义流程节点)

1.3.2 UML Activity Diagram

Flowportal BPM 的流程设计器

1.3.3 BPMN 系

activiti 的流程设计器

炎黄盈动的流程设计器

题外话:炎黄盈动的流程设计器,和 processon 中的流程设计器界面几乎一样,因为本质上是一家的。

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

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

2 流程引擎的应用

2.1 Workflow

工作流管理联盟 (Workflow Management Coalition,WfMC) 作为工作流管理的标准化组织而成立。

WfMC 对工作流给出定义为:工作流是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行。

在 workflow 中,流程引擎主要用于支撑流程审批和数据流转,应用场景非常广泛。

国外产品(开源或商用)通常需求和操作比较简单,不会有国内的需求那么复杂。国内的产品,经历了众多客户的锤炼,功能目前都比较强大。

一般而言,workflow 使用场景最多的是 OA 产品。在 OA 办公中,包含了企业办公中的大量元素,这些元素足够形成特定的产品,比如门户系统、移动办公。在 OA 的项目落地过程中,结合行业、业务侧重点又可以形成行业解决方案和专题方案。

以下是某 OA 公司产品和解决方案。

2.2 BPM(Business Process Management)

Workflow 主要是解决审批和数据流转,而 BPM 主要是解决端到端、信息孤岛等问题而存在的。大多数用 BPM 产品的客户,都是在 BPM 基础上进行系统搭建,比如在 BPM 上面搭建 OA、CRM、HR 等系统。

BPM 的使用场景,比 Workflow 更广泛,BPM 产品中包含大量的和第三方系统交互的组件和自定义 SQL、代码组件。

比如,BPM 系统中的文件触发器,可以在海关等交互场景下,通过监控 FTP 服务器中的文件,自动触发流程实例;可以通过定时器 Timer,自动每日执行数据同步,并通过 Mail 节点将同步结果通知到相关运营成员等。

BPM 的应用,可以按照执行前、执行中和执行后来划分。

2.3 流程编排

流程编排是脱离流程业务领域的更高一层抽象,使用方可以通过流程编排系统,结合自己的业务场景进行业务定制。比如,可以将相关业务代码,封装成 function,然后通过云厂商平台的 FAAS 平台,将不同业务的 function 进行关联和调度,从而完成某项任务。

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

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

3 流程引擎的架构设计

鉴于一些朋友可能没有使用和接触过流程引擎,先介绍流程引擎的组成单元,再介绍基于某个 BPM 产品的项目是如何进行开发的。我们通过 BPM 项目开发,对流程引擎的作用有个初步的认识。

3.1 BPM 流程引擎的组成单元

  • 组织、角色、用户、成员的组织架构托管;
  • 流程资源文件的配置、校验、存储和执行,对不同的流程节点,流程引擎自动结合配置、数据处理其对应的业务逻辑,流程数据自动处理;
  • 表单配置、数据绑定,表单数据的根据流程配置自动处理;
  • 通用的数据接口;
3.1.1 组织架构的设计
3.1.2 流程设计器

流程设计器包含左侧的分组节点列表,和右侧的画布。左侧的节点可以如下进行设计。

问题:对于一个 XML 或 JSON 格式的流程图,如何进行解析?

不同的节点,按照不同的业务场景,配置不同的配置项。比如,对于 Human Node 需要配置审批人,配置审批环节的展示表单,审批环节能够修改哪些字段,哪些字段的修改要进行留痕等。

3.1.3 表单设计器

这种是按照表单相关数据表,生成出一个表单,然后对表单字段进行配置和数据绑定。

这种是 Drag&Drop 控件,然后配置控件的属性,如绑定字段等。

这种是 Drag&Drop 控件,无需关联数据库表字段的表单

数据表生成表单的概要流程如下图所示。

拖拽控件绑定数据表字段的概要流程如下。

拖拽控件无需绑定数据表字段的概要流程。使用 NoSQL 的 Document 记录或使用 RDS 提供的 JSON 类型进行保存会比较方便。

3.1.4 接口设计

结合 Activity 的接口设计,如下图所示

一些系统在创建一个流程任务的时候,要先按照流程模板先创建一个应用示例,再关联发起人和备注,调用 RuntimeService ,执行到 StartNode,这类设计因人而异,这么做略显繁琐。

3.2 基于流程引擎的项目开发实践

3.2.1 流程项目实践流程
  • 确定组织架构
  • 确定流程,包括流程布局、审批人设置、权限
  • 确定表单信息(字段、类型、数据源、校验规则)和表单样式
  • 确定页面布局、样式、数据字段、搜索、导入、导出
  • 报表
3.2.2 组织架构

组织架构实现,有两种方法,一种是按照维度进行数据管理,另一种是在同一棵组织架构树下进行管理。

按照集团、公司、部门、用户等不同维度,进行数据管理,比较常见,这里不做讨论。下图为按维度维护数据的示例。

按照同一棵组织架构树进行数据维护,界面一般显示为左树右表。大多数商业化产品,都会将此组织架构树进行内存缓存,以方便审批人查找、开窗选择 OrgUnit、Role、User、Member 等场景。Member 的引入是为了解决一人多职等场景。一般发起流程的时候,需要带出发起人拥有的 Member 列表,从而后续节点取合适的审批人。

对于组织架构而言,需要考虑,系统本身要具备 OU 存储的能力,对于没有组织架构的用户,可以直接在系统的组织架构中新建组织架构。同时,对于已有系统的客户,可以通过组织架构数据同步来进行数据自动维护。对于用 AD 域内部管控的客户来说,需要具备 AD 域身份认证的能力。对于复杂场景,比如用户是 SaaS 化等复杂场景,组织架构也需要在系统内部,支持使用 API 的方式来获取组织信息。

所以在组织架构设计的时候,要使用插件的方式来做,具体使用哪种插件,可以在配置文件中进行配置。以下为一个商业产品的组织架构操作界面示例。

常见的组织架构操作还有组织架构同步,比如流程系统同步微信企业号、钉钉等,这里不再展开。

3.2.3 流程设计

我们想象的流程,可能是向下面的这种简单流程。

而实际项目,碰到的流程,一般是如下图所示的情景。

初步看几个流程的模型文件是什么样的,先有个印象。


<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>managementformalExpression>
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






请到「今天看啥」查看全文