一、前言
流程编排在业务需求中是一个非常普遍的场景,比如说涉及审批的工作流,涉及与调度顺序相关的任务流,涉及业务之间具有上下文数据传递关系的顺序流等,这类场景总结来说,就是众多的业务在逻辑上形成了可以按照业务内在的关联关系上的顺序流程,基于这样的场景,就是大家熟知的流程编排。
二、流程编排概述
2.1 什么是流程编排
流程编排(Process Orchestration)是指在一个多步骤的过程中,对各个独立的任务或服务进行协调和控制,使其按照预定的逻辑顺序和条件执行。简而言之,流程编排就是确保一系列相关任务能够按照正确的顺序和方式协同工作,以完成一个更大的目标或流程。
2.1.1 流程编排主要特征
流程编排具备如下特征:
- 协调与控制:确保各个任务按照预定的顺序和条件执行。
- 状态跟踪:记录各个任务的状态,以便于监控整个流程的进展。
- 异常处理:处理任务执行过程中可能出现的问题,如重试、回滚等。
- 资源管理:合理分配和管理执行任务所需的资源。
- 自动化执行:尽可能地减少人工干预,提高流程的自动化水平。
2.1.2 流程编排应用场景
流程编排具有丰富的使用场景,下面列举了一些常用的场景
- IT 自动化:在IT运维中,流程编排用于自动执行一系列任务,如服务器配置、软件部署、系统更新等。
- 业务流程管理:在企业管理中,流程编排用于协调和管理复杂的业务流程,如订单处理、供应链管理、客户服务等。
- DevOps:在软件开发领域,流程编排用于自动化构建、测试和部署过程,即CI/CD(持续集成/持续部署)管道。
- 微服务架构:在微服务架构中,流程编排用于协调多个服务之间的交互,确保服务之间按正确顺序调用。
2.2 流程编排与工作流区别
很多同学容易把流程编排与工作流弄混,其实两者之间还是有一些区别的,具体来说,体现在下面几个方面:
2.2.1 定义上的差别
- 工作流 (Workflow)- 定义:工作流是一系列任务的有序集合,这些任务按照预定的规则和顺序执行。它侧重于描述业务过程中的步骤和顺序。- 关注点:工作流更多地关注于业务流程本身,即任务是如何被启动、执行、监控和结束的。- 例子:员工报销流程、采购申请流程、客户服务请求处理等。
- 流程编排 (Process Orchestration)- 定义:流程编排是在更高层次上对多个任务或服务进行协调,确保它们按照正确的顺序和依赖关系执行。它侧重于多个系统或服务之间的交互和协调。- 关注点:流程编排侧重于跨多个服务或系统的任务调度和状态管理,确保整体流程的连贯性和一致性。- 例子:CI/CD管道中的构建、测试和部署流程;多服务架构下的事务处理。
2.2.2 应用场景上的差别
- 工作流 (Workflow)- 应用场景:通常用于企业内部的各种业务流程管理,如审批流程、文档流转、任务分配等。- 工具:常见的工作流管理工具包括BPMN(Business Process Model and Notation)工具、Activiti、Bonita、Camunda等。
- 流程编排 (Process Orchestration)- 应用场景:广泛应用于IT自动化、微服务架构中的服务交互、云原生环境下的任务调度等。- 工具:常用的流程编排工具包括Kubernetes(用于容器编排)、Apache Airflow(用于数据管道编排)、AWS Step Functions等。
2.2.3 技术实现上的差异
- 工作流- 实现方式:通常通过工作流引擎来实现,这些引擎可以是基于规则的,也可以是图形化的。- 语言:工作流可以使用特定的工作流定义语言(如BPMN XML)来描述流程。
- 流程编排- 实现方式:通过编排工具来实现,这些工具往往需要处理复杂的依赖关系和服务交互。- 语言:流程编排可能会使用编程语言(如Python、Java)编写代码来实现,也可能会使用特定的编排语言(如YAML用于Kubernetes)。
总结来说:
- 工作流更侧重于业务流程本身,强调的是任务的顺序和状态。
- 流程编排则更侧重于多个服务或系统之间的协调,强调的是整体流程的一致性和连贯性。
两者并不是完全独立的概念,在实际应用中往往会有交叉。例如,在一个CI/CD流程中,工作流可以用来描述具体的构建和测试步骤,而流程编排则用来确保这些步骤在整个部署过程中被正确地执行。
三、微服务中流程编排常用的技术
在微服务开发中,经过多年的发展,流程编排的技术经过很多产品的实践和应用,出现了很多比较成熟的开源解决方案,下面列举一些可用于实现流程编排的技术组件。
3.3.1 LiteFlow
LiteFlow 是一个轻量级、高性能的流程编排框架,专注于简单易用。主要有下面的特点:
- 支持多种流程定义方式(如 YAML、JSON、XML)。
- 支持自定义节点和执行逻辑。
- 高性能,适用于高并发场景。
适用于需要快速定义和执行复杂业务流程的应用。
3.3.2 EasyFlow
EasyFlow 是一个轻量级的流程编排框架,专注于简化流程定义和执行。主要有下面的特点:
- 支持多种流程定义方式。
- 配置简单,支持多种执行策略。
适用于需要快速定义和执行简单业务流程的应用。
3.3.3 jBPM
虽然 jBPM 是一个相对成熟的流程编排框架,但它的轻量级版本可以用于简单的流程管理。主要有下面的特点:
- 支持 BPMN 2.0 标准,可以用于复杂流程编排。
- 可以选择仅使用核心功能,保持轻量级。
适用于需要 BPMN 支持的轻量级流程编排
3.3.4 Spring StateMachine
Spring StateMachine也叫状态机, 是 Spring Framework 的一部分,用于实现有限状态机。
- 支持定义状态机,可以用于流程编排。
- 集成到 Spring 应用程序中非常方便。
适用于需要状态机功能的流程编排
3.3.5 Jodd
Jodd 是一个多功能的 Java 工具箱,其中包含了流程编排的相关功能。其具备如下特点:
- 提供了一系列工具类,支持多种功能,包括流程编排。
- 轻量级,易于集成。
适用于需要多功能工具箱的应用
3.3.6 Fluent Bit
Fluent Bit 是一个轻量级的日志处理器,虽然主要用于日志处理,但也可用于简单的流程编排。
- 支持多种插件,可以进行日志处理、转发等。
- 配置简单,支持多种输出目的地。
3.3.7 CompileFlow
CompileFlow 是一个轻量级的流程编排框架,专门为 Java 应用程序设计,旨在简化流程定义和执行。它的设计目的是让开发者能够快速构建和管理复杂的业务流程,同时保持代码的清晰和可维护性。
CompileFlow 的特点:
- 轻量级:CompileFlow 是一个非常轻量级的框架,没有复杂的配置和大量的依赖。
- 易用性:提供简洁的 API 和 DSL(领域特定语言),使流程定义变得简单直观。
- 灵活性:支持多种流程定义方式,可以很容易地定义复杂的业务流程。
- 高性能:采用高效的执行机制,适合高并发场景。
- 易于集成:可以轻松集成到现有的 Java 应用程序中,支持 Spring Boot 等主流框架
适用场景:
- 数据处理:如数据采集、清洗、存储等。
- 批处理作业:如定时任务、批处理等。
- 业务流程管理:如订单处理、审批流程等。
四、LiteFlow介绍
4.1 什么是LiteFlow
LiteFlow 是一个轻量级的流程编排框架,专为 Java 应用程序设计。它的主要特点包括易用性、灵活性和高性能。LiteFlow 适用于需要快速定义和执行复杂业务流程的场景。官方地址:LiteFlow
4.2 LiteFlow 特点
LiteFlow 具备如下特点:
- 轻量级- LiteFlow 极其轻量,没有复杂的配置和大量的依赖;- LiteFlow 的核心设计思想之一就是保持框架本身的轻量性,使得它不会对应用程序产生过多的负担。这使得它非常适合嵌入到现有的 Java 应用程序中,而不需要额外的服务器或复杂的部署过程。
- 易用性- 提供简单直观的流程定义方式,支持多种格式(如 YAML、JSON、XML);- LiteFlow 设计得非常易于使用,开发者可以快速上手并开始定义流程。它的配置文件简单明了,支持 YAML 和 JSON 格式,使得流程定义变得直观。
- 可扩展性好- LiteFlow 提供了良好的扩展机制,开发者可以根据需要自定义组件和插件,以适应各种业务场景的需求。此外,LiteFlow 的架构设计允许在不影响现有流程的情况下轻松添加新的功能。
- 灵活性- 支持多种类型的流程定义和复杂的流程逻辑。- LiteFlow 支持多种流程模式,包括顺序执行、分支执行、循环执行等。同时,它还支持动态加载流程定义,这意味着流程可以在运行时根据需要动态更改。
- 组件丰富- LiteFlow 内置了许多组件,如条件判断、循环、分支等,这些组件可以帮助开发者快速构建复杂的流程。此外,开发者还可以自定义组件以满足特定的需求。
- 高性能- 采用高效的执行机制,适合高并发场景。- LiteFlow 支持并发处理,这意味着它可以有效地处理并发请求。这对于需要在高并发环境下运行的应用程序来说非常重要。
- 易于集成- 可以轻松集成到现有的 Java 应用程序中,支持 Spring Boot 等主流框架。
- 社区和支持- LiteFlow 拥有一个活跃的社区,开发者可以在这里获得帮助和支持。此外,LiteFlow 的文档和示例也非常丰富,可以帮助开发者快速入门。
- 插件化设计- LiteFlow 支持插件化设计,这意味着可以通过插件的形式来扩展框架的功能,而不必修改框架本身的核心代码。
4.3 LiteFlow 适用场景
LiteFlow 作为一个轻量级的流程编排框架,适用于多种场景,特别是在需要定义和执行复杂业务流程的情况下。以下是一些典型的适用场景:
- 业务流程管理(BPM)- 适用场景:需要定义和执行复杂的业务流程,如订单处理、审批流程、工作流等。- 例子:一个电商平台中的订单处理流程,包括订单接收、库存检查、支付确认、发货准备、物流跟踪等。
- 数据处理- 适用场景:需要处理和转换大量数据的情况,如数据采集、数据清洗、数据存储等。- 例子:从多个数据源采集数据,然后进行清洗、转换,并最终存储到数据库中。
- 批处理任务- 适用场景:需要定期执行的批处理任务,如定时备份、报表生成等。- 例子:每天凌晨自动备份数据库,并将备份文件上传至远程服务器。
- 事件驱动的应用- 适用场景:需要根据特定事件触发一系列动作的情况,如订单状态变更、用户行为追踪等。- 例子:当用户提交订单后,触发一系列后台任务,如发送确认邮件、更新库存、通知物流公司等。
- 微服务协调- 适用场景:在微服务架构中,需要协调多个服务之间的交互。- 例子:一个订单服务可能需要与库存服务、支付服务、物流服务等多个微服务进行交互,LiteFlow 可以用于定义和执行这些服务之间的协调流程。
- 测试用例执行- 适用场景:需要执行复杂的测试用例,包括前置条件设置、测试步骤执行、结果验证等。- 例子:自动化测试框架中,定义一个复杂的测试流程,包括环境准备、测试执行、结果记录等。
- 工作流管理- 适用场景:需要管理多个参与者之间的协作流程,如审批流程、任务分配等。- 例子:一个企业的报销流程,包括员工提交报销单、主管审批、财务审核、最终支付等。
- 状态机实现- 适用场景:需要实现有限状态机的情况,如订单状态机、工作流状态机等。- 例子:一个订单状态机,包括待支付、已支付、已发货、已完成等多个状态,以及状态之间的转换逻辑。
4.4 LiteFlow整体架构解析
下图为LiteFlow整体架构图
关于架构图中涉及的几个核心组件做如下说明
4.4.1 Parser
- 该组件作用是用来解析流程配置的规则,也就是将你配置的规则文件解析成Java代码来运行。- 支持的文件格式有xml、json、yaml,其实不论是什么格式,只是形式的不同,用户可根据自身配置的习惯来选择规则文件的格式。
- 对于xml来说,Parser会将<node/>标签解析成Node对象,将<chain/>解析成Chain对象,将<chain/>内部的比如<when/>、<then/>等标签都会解析成Condition对象。如下图所示。- Node代表了你具体业务执行的节点,就是真正的业务是在Node中执行的;- Condition可以理解为一种条件,比如前置条件,后置条件,里面一个Condition可以包含许多需要执行的Node;- Chain可以理解成整个业务执行的流程,按照一定的顺序来执行Condition中的Node也就是业务节点;
Condition和Node的关系
- Condition分为以下几种- PreCondition:在整个业务执行前执行,就是前置的作用- ThenCondition:内部的Node是串行执行的- WhenCondition:内部的Node是并行执行的- FinallyCondition:当前面的Condition中的Node都执行完成之后,就会执行这个Condition中的Node节点
Chain和Condition的关系
Chain内部其实就是封装了一堆Condition,Chain的执行就是指从不同的Condition中拿出里面的Node来执行,首先会拿出来PreCondition中的Node节点来执行,执行完之后会执行ThenCondition和WhenCondition中的Node节点,最后执行完之后才会执行FinallyCondition中的Node节点。
4.4.2 FlowBus
这个组件主要是用来存储上一步骤解析出来的Node和Chain
4.4.3 FlowExecutor
FlowExecutor用来执行上面解析出来的业务流程,从FlowBus找到需要执行的业务流程Chain,然后执行Chain,也就是按照Condition的顺序来分别执行每个Condition的Node,也就是业务节点
4.4.4 Slot
Slot可理解为业务上下文,在一个业务流程中,这个Slot是共享的,有点像springcontext的作用,在组件的底层,存储的是一个Map结构。
Slot有个默认的实现DefaultSlot,DefaultSlot虽然可以用,但是在实际业务中,用这个会存在大量的弱类型,存取数据的时候都要进行强转,颇为不方便。所以官方建议自己去实现自己的Slot,可以继承AbsSlot。
4.4.5 DataBus
用来管理Slot的,可以获取当前业务流程执行的Slot
4.5 LiteFlow 核心概念
在正式开始学习LiteFlow 之前,需要先了解并掌握LiteFlow 中的几个核心概念吗,以便后续更好的理解其原理,LiteFlow 的核心概念主要包括以下几个部分:
- 节点(Node)- 定义:节点是流程中的最小执行单元,可以是任何业务逻辑的封装。- 作用:每个节点代表一个具体的业务操作,如数据采集、数据清洗、数据存储等。- 实现:节点通常由 Java 类实现,继承自
NodeComponent
或其子类。 - 链(Chain)- 定义:链是一组按顺序执行的节点集合。- 作用:链定义了节点的执行顺序,可以包含多个节点,按照指定的顺序依次执行。- 实现:链通常在流程定义文件中定义,可以使用 YAML、JSON 或 XML 格式来描述。
- 流程(Flow)- 定义:流程是一个或多个链的组合,代表一个完整的业务流程。- 作用:流程定义了整个业务逻辑的执行顺序,可以包含多个链,按照指定的顺序依次执行。- 实现:流程也在流程定义文件中定义,可以包含多个链,并定义它们的执行顺序。
- 流程定义文件- 定义:流程定义文件是用来描述流程、链和节点之间关系的文件。- 格式:支持多种格式,如 YAML、JSON 或 XML。- 作用:流程定义文件描述了整个流程的结构和逻辑,使得流程的定义和维护变得更加直观和方便。
- 执行上下文(ExecutionContext)- 定义:执行上下文是在流程执行过程中传递的数据对象。- 作用:用于在节点之间传递数据,每个节点可以访问和修改执行上下文中的数据。- 实现:通常在流程执行过程中通过方法参数传递。
- 条件分支(Conditional Branch)- 定义:条件分支是根据一定的条件选择不同的执行路径。- 作用:使得流程可以根据业务逻辑的不同条件选择不同的执行路径。- 实现:可以在流程定义文件中使用条件表达式来定义条件分支。
- 循环(Loop)- 定义:循环是重复执行某一段逻辑的机制。- 作用:使得流程可以根据需要重复执行某些节点。- 实现:可以在流程定义文件中使用循环语句来定义循环逻辑。
- 异常处理(Exception Handling)- 定义:异常处理是在流程执行过程中处理异常情况的机制。- 作用:确保流程在遇到错误时能够正确处理,并继续执行或停止执行。- 实现:可以通过捕获异常并在流程定义文件中定义异常处理逻辑来实现。
五、LiteFlow 整合springboot操作实践
通过上文的学习,基本上了解了LiteFlow 的全貌,接下来通过在springboot工程中集成LiteFlow ,掌握如何具体使用LiteFlow 。
github : GitHub - dromara/liteflow: Lightweight, fast, stable, and programmable component-based rule engine/process engine. Component reuse, synchronous/asynchronous orchestration, dynamic orchestration, multi-language scripting support, complex nested rules, hot deployment, smooth refreshing. Let you improve your development efficiency!
gitee源码地址:liteFlow: 轻量,快速,稳定,可编排的组件式规则引擎/流程引擎。拥有全新设计的DSL规则表达式。组件复用,同步/异步编排,动态编排,支持超多语言脚本,复杂嵌套规则,热部署,平滑刷新规则等等功能,让你加快开发效率!
中文文档地址:🍤LiteFlow简介 | LiteFlow
5.1 前置准备
提前搭建一个springboot工程,导入下面核心依赖
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
5.2 快速开始案例一:顺序编排
官方也提供了参考学习案例操作文档,下面先以官方案例为指导,完成一个入门案例的操作
5.2.1 引入liteflow依赖
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.12.3</version>
</dependency>
5.2.2 设置要执行的组件
在依赖了以上jar包后,你需要定义并实现一些组件,确保SpringBoot会扫描到这些组件并注册进上下文。下面是本次案例中要完成的一个编排任务涉及到的3个组件。
组件A:
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component("a")
@Slf4j
public class ComponentA extends NodeComponent {
@Override
public void process() throws Exception {
log.info("ComponentA process()");
String strA = this.getSlot().getRequestData();
log.info("ComponentA requestData :【{}】",strA);
//重新将参数设置到Slot里面去
this.getSlot().setOutput(this.getNodeId(),strA + " -- > A component");
log.info("ComponentA process() finished");
}
}
组件B
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component("b")
@Slf4j
public class ComponentB extends NodeComponent {
@Override
public void process() throws Exception {
Thread.sleep(50);
log.info("ComponentB process()");
String inputStrA = this.getSlot().getOutput("a");
log.info("ComponentB get inputStrA :【{}】",inputStrA);
//重新将参数设置到Slot里面去
this.getSlot().setOutput(this.getNodeId(),inputStrA + " -- > B component");
log.info("ComponentB process() finished");
}
}
组件C
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component("c")
@Slf4j
public class ComponentC extends NodeComponent {
@Override
public void process() throws Exception {
Thread.sleep(50);
log.info("ComponentC process()");
String inputStrB = this.getSlot().getOutput("b");
log.info("ComponentC get inputStrB :【{}】",inputStrB);
//重新将参数设置到Slot里面去
this.getSlot().setOutput(this.getNodeId(),inputStrB + " -- > C component");
log.info("ComponentC process() finished");
}
}
5.2.3 配置文件信息
在application.yml中配置编排xml文件的扫描路径
server:
port: 8087
#扫描文件
liteflow:
rule-source: config/**/*.el.xml
5.2.4 设置flow.el.xml
如何将上面的几个组件按照流程图中的顺序进行执行呢,就需要在此xml文件中进行定义和配置,如下
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
THEN(a, b, c);
</chain>
</flow>
配置文件中各节点标签的含义可以参考上文以及官方文档进行深入的理解,在实际应用中也是通过这个文件将代码中的各个组件在这里配置从而实现某种顺序,或按照条件执行
5.2.5 配置启动类
LiteFlow中的各个组件要能按顺序调动执行,需要配置一个执行器,如下:
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class FlowCommand implements CommandLineRunner {
@Resource
private FlowExecutor flowExecutor;
@Override
public void run(String... args) throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
System.out.println("chain1 res : " + response);
}
}
这个DefaultContext是默认的上下文,用户可以用最自己的任意Bean当做上下文传入,如果需要传入自己的上下文,则需要传用户Bean的Class属性,具体可以参考官网文档进行配置
5.2.6 启动项目
启动项目之后,通过控制台的输出可以看到3个组件已经按照预期的顺序执行了
5.3 快速开始案例二:条件选择编排
在实际业务中,编排的任务场景并非是一条顺序执行那么简单,像下面这样,从某个节点到下一个节点需要条件判断,这个在liteflow中也叫条件选择,参考下面的操作步骤
对应的官方文档:🌾选择编排 | LiteFlow
5.3.1 增加一个D组件
代码如下
@Component("d")
@Slf4j
public class ComponentD extends NodeComponent {
@Override
public void process() throws Exception {
Thread.sleep(50);
log.info("ComponentD process()");
String inputStrB = this.getSlot().getOutput("b");
log.info("ComponentD get inputStrB :【{}】",inputStrB);
//重新将参数设置到Slot里面去
this.getSlot().setOutput(this.getNodeId(),inputStrB + " -- > D component");
log.info("ComponentD process() finished");
}
}
5.3.2 增加一个选择组件
在实际业务中,通过该组件进行判断从B组件出去之后具体走到C还是D,在这段代码中,我们手动指定了下一个节点为c
import com.yomahub.liteflow.core.NodeSwitchComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component("bb")
@Slf4j
public class ComponentBB extends NodeSwitchComponent {
@Override
public String processSwitch() throws Exception {
log.info("ComponentBB processSwitch");
String inputStrA = this.getSlot().getOutput("a");
log.info("ComponentBB get inputStrA :【{}】",inputStrA);
//重新将参数设置到Slot里面去
this.getSlot().setOutput(this.getNodeId(),inputStrA + " -- > BB component");
return "c";
}
}
5.3.3 在xml文件中配置表达式
表达式的配置方式有多种,下面根据官方文档的说明,结合案例中的场景提供的一种配置
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain2">
THEN(
a,
SWITCH(bb).to(
c,
THEN(d)
)
);
</chain>
</flow>
5.3.4 效果测试
项目启动并运行,控制台可以看到如下效果,说明条件选择生效了
liteflow提供了丰富的组件满足日常开发中的各类编排场景,上面列举了2个基本的使用案例,有兴趣的同学可以进一步参考官网文档进行学习实践。
5.4 springboot 项目中整合实践
下面以一个具体的业务场景为例,详细说明如何在springboot项目中整合使用liteflow。
案例需求描述
实现一个任务的编排,依次按照下面的顺序执行:
- 初始化节点信息
- 创建订单
- 增加积分
- 扣减库存
5.4.1 增加需求描述节点类
初始化节点
import com.congge.entity.Order;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@LiteflowComponent(id = "InitNode",name = "流程启动节点")
@Component
@Slf4j
public class InitNode extends NodeComponent {
@Override
public void process() throws Exception {
ProcessFlowContext context = this.getContextBean(ProcessFlowContext.class);
Order order = new Order();
order.setOrderId("0001");
order.setProductList(context.getProductList());
context.setOrder(order);
log.info("流程启动...");
}
}
创建订单节点
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@LiteflowComponent(id = "CreateOrder",name = "创建订单节点")
@Component
@Slf4j
public class CreateOrder extends NodeComponent {
@Override
public void process() throws Exception {
log.info("创建订单节点开始执行 ...");
ProcessFlowContext context = this.getContextBean(ProcessFlowContext.class);
String orderId = context.getOrder().getOrderId();
log.info("创建订单节点业务执行,orderId :【{}】",orderId);
}
}
增加积分节点
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@LiteflowComponent(id = "AddScore",name = "增加积分节点")
@Component
@Slf4j
public class AddScore extends NodeComponent {
@Override
public void process() throws Exception {
log.info("增加积分节点开始执行 ...");
ProcessFlowContext context = this.getContextBean(ProcessFlowContext.class);
String orderId = context.getOrder().getOrderId();
log.info("增加积分节点业务执行,orderId :【{}】",orderId);
context.getResultMap().put("score",1000);
}
}
扣减库存节点
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@LiteflowComponent(id = "MinusStore",name = "扣减库存节点")
@Component
@Slf4j
public class MinusStore extends NodeComponent {
@Override
public void process() throws Exception {
log.info("扣减库存节点节点开始执行 ...");
ProcessFlowContext context = this.getContextBean(ProcessFlowContext.class);
String orderId = context.getOrder().getOrderId();
log.info("扣减库存节点业务执行,orderId :【{}】",orderId);
context.getResultMap().put("store",99);
}
}
ProcessFlowContext类,为传递各个节点执行过程中产生的参数或结果
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Data
public class ProcessFlowContext {
Order order;
List<Product> productList = new ArrayList<>();
Map<String,Object> resultMap = new LinkedHashMap<>();
}
5.4.2 配置流程节点编排文件
在config目录下增加order.el.xml文件,配置信息如下
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="order-chain">
THEN(
InitNode,
CreateOrder,
AddScore,
MinusStore
);
</chain>
</flow>
5.4.3 增加测试接口
增加如下测试接口
import com.congge.entity.Product;
import com.congge.node.ProcessFlowContext;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RequestMapping("/order")
@RestController
@Slf4j
public class OrderController {
@Resource
private FlowExecutor flowExecutor;
//localhost:8087/order/create
@GetMapping("/create")
public String createOrder(){
ProcessFlowContext context = new ProcessFlowContext();
context.getProductList().add(new Product("1","手机"));
context.getProductList().add(new Product("2","家电"));
LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("order-chain", null, context);
ProcessFlowContext resContext = liteflowResponse.getContextBean(ProcessFlowContext.class);
log.info("orderId : {},score :{},store : {}",
resContext.getOrder().getOrderId(),
resContext.getResultMap().get("score"),
resContext.getResultMap().get("store")
);
return "order created";
}
}
5.4.4 效果测试
启动工程后,调用一下接口,通过控制台输出可以看到相关节点的逻辑已经按照编排文件中的顺序输出了
5.4.5 补充说明
在实际业务中,不同的节点可能都对应着某个模块的业务,正常的业务逻辑开发保持不变,只是在需要传递变量或结果参数给其他节点使用时按照约定规则设置到ProcessFlowContext即可。
六、写在文末
本文通过较大的篇幅详细介绍了规则编排引擎liteflow的详细使用,并通过案例演示了其使用细节,在实际业务中也有着一定的参考意义,希望对看到的同学有用,本篇到此结束,感谢观看。
版权归原作者 小码农叔叔 所有, 如有侵权,请联系我们删除。