springboot 集成轻量级规则编排引擎 LiteFlow 使用详解

news2024/9/21 17:04:35

目录

一、前言

二、流程编排概述​​​​​​​

2.1 什么是流程编排

2.1.1 流程编排主要特征

2.1.2 流程编排应用场景

2.2 流程编排与工作流区别

2.2.1 定义上的差别

2.2.2 应用场景上的差别

2.2.3 技术实现上的差异

三、微服务中流程编排常用的技术

3.3.1 LiteFlow

3.3.2 EasyFlow

3.3.3 jBPM

3.3.4 Spring StateMachine

3.3.5 Jodd

3.3.6 Fluent Bit

3.3.7 CompileFlow

四、LiteFlow介绍

4.1 什么是LiteFlow

4.2 LiteFlow 特点

4.3 LiteFlow 适用场景

4.4 LiteFlow整体架构解析

4.4.1 Parser

4.4.2 FlowBus

4.4.3 FlowExecutor

4.4.4 Slot

4.4.5 DataBus

4.5 LiteFlow 核心概念

五、LiteFlow 整合springboot操作实践

5.1 前置准备

5.2 快速开始案例一:顺序编排

5.2.1 引入liteflow依赖

5.2.2 设置要执行的组件

5.2.3 配置文件信息

5.2.4 设置flow.el.xml

5.2.5 配置启动类

5.2.6 启动项目

5.3 快速开始案例二:条件选择编排

5.3.1 增加一个D组件

5.3.2 增加一个选择组件

5.3.3 在xml文件中配置表达式

5.3.4 效果测试

5.4 springboot 项目中整合实践

5.4.1 增加需求描述节点类

5.4.2 配置流程节点编排文件

5.4.3 增加测试接口

5.4.4 效果测试

5.4.5 补充说明

六、写在文末


一、前言

流程编排在业务需求中是一个非常普遍的场景,比如说涉及审批的工作流,涉及与调度顺序相关的任务流,涉及业务之间具有上下文数据传递关系的顺序流等,这类场景总结来说,就是众多的业务在逻辑上形成了可以按照业务内在的关联关系上的顺序流程,基于这样的场景,就是大家熟知的流程编排。

二、流程编排概述

2.1 什么是流程编排

流程编排(Process Orchestration)是指在一个多步骤的过程中,对各个独立的任务或服务进行协调和控制,使其按照预定的逻辑顺序和条件执行。简而言之,流程编排就是确保一系列相关任务能够按照正确的顺序和方式协同工作,以完成一个更大的目标或流程。

2.1.1 流程编排主要特征

流程编排具备如下特征:

  1. 协调与控制:确保各个任务按照预定的顺序和条件执行。

  2. 状态跟踪:记录各个任务的状态,以便于监控整个流程的进展。

  3. 异常处理:处理任务执行过程中可能出现的问题,如重试、回滚等。

  4. 资源管理:合理分配和管理执行任务所需的资源。

  5. 自动化执行:尽可能地减少人工干预,提高流程的自动化水平。

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 的特点

  1. 轻量级:CompileFlow 是一个非常轻量级的框架,没有复杂的配置和大量的依赖。

  2. 易用性:提供简洁的 API 和 DSL(领域特定语言),使流程定义变得简单直观。

  3. 灵活性:支持多种流程定义方式,可以很容易地定义复杂的业务流程。

  4. 高性能:采用高效的执行机制,适合高并发场景。

  5. 易于集成:可以轻松集成到现有的 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的详细使用,并通过案例演示了其使用细节,在实际业务中也有着一定的参考意义,希望对看到的同学有用,本篇到此结束,感谢观看。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2142561.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车型展示+接驳体验!苏州金龙海格客车闪耀汉诺威商用车展

德国当地时间9月16日&#xff0c;IAA汉诺威商用车展媒体日活动在德国汉诺威展览中心开幕。该展会自1897年首次举办以来&#xff0c;已有超过一个世纪的历史&#xff0c;是全球历史最长、规模最大、最具影响力的专业商用车展之一&#xff0c;更是世界商用车行业技术创新和发展趋…

【Java宝典】——探索数组的奥秘之旅

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 Java数组常见报错①:ArrayIndexOutOfBoundsException(数组索引超出范围)②:NullPointerException(空…

【数字组合】

题目 思路 状态表示&#xff1a; f [ i ] [ j ] f[i][j] f[i][j] 对应考虑1到 i 号数字&#xff0c;和为 j 的方法&#xff0c;表示方法数 目标表示&#xff1a; f [ n ] [ m ] f[n][m] f[n][m] 状态转移&#xff1a; f [ i ] [ j ] f [ i − 1 ] [ j ] f [ i − 1 ] [ j …

2022高教社杯全国大学生数学建模竞赛C题 问题二(1) Python代码

目录 问题 22.1 依据附件数据分析高钾玻璃、铅钡玻璃的分类规律数据类别编码不平衡数据处理分类模型决策树分类随机森林分类XGBoost分类LightGBM分类Catboost分类基于直方图的梯度提升Histogram-Based Gradient Boosting梯度提升树Gradient Boosting Tree逻辑回归Logistic朴素贝…

Python | Leetcode Python题解之第409题最长回文串

题目&#xff1a; 题解&#xff1a; class Solution:def longestPalindrome(self, s: str) -> int:ans 0count collections.Counter(s)for v in count.values():ans v // 2 * 2if ans % 2 0 and v % 2 1:ans 1return ans

【快速入门】UMLS使用手册官方-超全翻译(包括图与表翻译)

目录 第 1 章 UMLS 简介 第 2-4 章。元同义词库 第 5 章 语义网络 第 6 章 专业词汇和词汇工具 第 7 章 UMLS 术语服务 第 8 章 MetamorphoSys 1 UMLS 简介 1.1. UMLS 的目的 1.2. UMLS 的使用条件 1.3. UMLS 知识源和相关工具 1.3.1. 元同义词库 1.3.2. 语义网络 …

【网络安全 | PHP代码审计】熊海cms

原创文章,禁止转载。 文章目录 环境搭建代码审计文件包含漏洞SQL注入漏洞1SQL注入漏洞2SQL注入漏洞3SQL注入漏洞4SQL注入漏洞5SQL注入漏洞6XSS漏洞1XSS漏洞2垂直越权CSRF1CSRF2逻辑漏洞环境搭建 https://down.chinaz.com/soft/36930.htm解压并重命名: 修改配置(php版本需…

【Git】将本地项目上传到git | 在IDEA的提交记录中更改 提交的用户名

一:将本地项目上传到git 1:在​gitee​上创建以自己项目名称命名的空项目【注意项目名称与本地项目的文件夹名称一致】 2:进入想上传的项目的文件夹,然后右键点击 3:查看用户名及邮箱 $ git config user.name $ git config user.email4: 配置你的用户名及邮箱【如果有…

Git:Git管理

目录 Git 文件管理检测文件状态 status跟踪新文件 add提交更新 commit撤销提交 Commit Git 校验和历史查看 log版本回退 resetgit 忽略文件 Git 分支管理Git 提交对象Git master分支Git 分支管理本地分支管理远程分支管理分支hotfix处理 Git 工作流常见分支冲突处理分支合并冲突…

形象化展示numpy.stack

https://numpy.org/doc/stable/reference/generated/numpy.stack.html#numpy.stack 1. 一维数组 import numpy as npa np.arange(4) b np.arange(4) c np.stack([a,b]) d np.stack([a,b], axis1) print(a -->, a.shape,:\n, a) print(b -->, b.shape,:\n, b) print…

ICM20948 DMP代码详解(25)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;24&#xff09; 上一回讲到了inv_icm20948_load_firmware函数&#xff0c;对于大体功能进行了介绍&#xff0c;本回深入其具体实现代码细节。为了便于理解和回顾&#xff0c;再次贴出相关代码&#xff1a; //Setup Iv…

【个人博客hexo版】hexo安装时会出现的一些问题

项目场景&#xff1a; 项目场景&#xff1a;在完成了GitHub仓库和git的连接之后&#xff0c;就要新建一个文件夹&#xff08;例如hexo blog&#xff09;进行下一步hexo的使用 问题描述 例如&#xff1a;如图所示 原因分析&#xff1a; 这些error不用看它到底是什么&#xf…

Chrome谷歌浏览器登录账号next无反应

文章目录 问题描述 我们的Chrome浏览器在更新之后&#xff0c;会出现登录谷歌账号的时候&#xff0c;当你输入你的谷歌邮箱之后&#xff0c;点击 n e x t next next,也就是下一步的时候&#xff0c;页面没有反应&#xff0c;也就是没有跳转到输入密码的页面。 分析 根据logs里…

CLIP模型也能处理点云信息(论文复现)

CLIP模型也能处理点云信息&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 文章目录 CLIP模型也能处理点云信息&#xff08;论文复现&#xff09;概述模型结构模型总览图点云的投影视图间适配器 演示效果零样本投影少样本投影 核心逻辑使用方式部署…

Mamba环境配置教程【自用】

1. 新建一个Conda虚拟环境 conda create -n mamba python3.102. 进入该环境 conda activate mamba3. 安装torch&#xff08;建议2.3.1版本&#xff09;以及相应的 torchvison、torchaudio 直接进入pytorch离线包下载网址&#xff0c;在里面寻找对应的pytorch以及torchvison、…

VTD激光雷达(5)——05_OptiX_GPU

文章目录 前言一、总结 前言 一、 1 2 3 总结

随着访问范围的扩大 OpenAI o1-mini 现已向免费用户开放

上周&#xff0c;OpenAI 展示了其最新的大型语言模型&#xff08;LLM&#xff09;–OpenAI o1及其小兄弟 OpenAI o1-mini。该公司在公告中称&#xff0c;Plus 和 Team 用户可在公告发布之日起访问该模型。企业和教育用户将在本周获得该模型&#xff0c;而免费用户最终将获得 o1…

线性代数之QR分解和SVD分解

文章目录 1.QR分解Schmidt正交化Householder变换QR分解的应用 2. 求矩阵特征值、特征向量的基本方法3.SVD分解SVD分解的应用 参考文献 1.QR分解 矩阵的正交分解又称为QR分解&#xff0c;是将矩阵分解为一个正交矩阵Q和一个上三角矩阵R的乘积的形式。 任意实数方阵A&#xff0c…

2022高教社杯全国大学生数学建模竞赛C题 问题一(1) Python代码

目录 问题 11.1 对这些玻璃文物的表面风化与其玻璃类型、纹饰和颜色的关系进行分析数据探索 -- 单个分类变量的绘图树形图条形图扇形图雷达图Cramer’s V 相关分析统计检验列联表分析卡方检验Fisher检验绘图堆积条形图分组条形图分类模型Logistic回归随机森林import matplotlib…

SpaceX实现人类首次商业太空行走:航天历史新篇章

导语 2023年9月&#xff0c;SpaceX成功完成了人类历史上首次商业太空行走&#xff0c;这不仅是航天领域的重要突破&#xff0c;也是商业航天的一次重大胜利。这一事件标志着普通人离太空更近了一步&#xff0c;为未来的太空探索和火星移民奠定了基础。 一、背景介绍&#xff1a…