SpringBoot中集成LiteFlow(轻量、快速、稳定可编排的组件式规则引擎)实现复杂业务解耦、动态编排、高可扩展

场景

在业务开发中,经常遇到一些串行或者并行的业务流程问题,而业务之间不必存在相关性。

使用策略和模板模式的结合可以解决这个问题,但是使用编码的方式会使得文件太多,

在业务的部分环节可以这样操作,在项目角度就无法一眼洞穿其中的环节和逻辑。

一些拥有复杂业务逻辑的系统,核心业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。

时间一长,维护的成本就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。

一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。

如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。

实时热变更业务流程,几乎很难实现 。

LiteFlow

LiteFlow就是为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。

它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件,

并支持热加载规则配置,实现即时修改。

使用LiteFlow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。

这样,所有的组件,就能按照你的规则配置去进行复杂的流转。

LiteFlow官方网站:

LiteFlow

LiteFlow的Gitee地址:

liteFlow: 轻量,快速,稳定,可编排的组件式规则引擎/流程引擎。拥有全新设计的DSL规则表达式。组件复用,同步/异步编排,动态编排,支持超多语言脚本,复杂嵌套规则,热部署,平滑刷新规则等等功能,让你加快开发效率!

LiteFlow的特点:

注:

博客:
霸道流氓气质-CSDN博客

实现

1、SpringBoot中集成LiteFlow

LiteFlow要求的Springboot的最低的版本是2.0。

支持的范围是Springboot 2.X ~ Springboot 3.X。

LiteFlow提供了liteflow-spring-boot-starter依赖包,提供自动装配功能

<dependency><groupId>com.yomahub</groupId><artifactId>liteflow-spring-boot-starter</artifactId><version>2.11.4.2</version>
</dependency>

2、SpringBoot中配置LiteFlow

在你的SpringBoot的application.properties或者application.yml里添加配置

#liteflow规则配置文件位置
liteflow:rule-source: config/flow.el.xml

规则文件的定义

在resources下的config/flow.el.xml中定义规则:

<?xml version="1.0" encoding="UTF-8"?>
<flow><chain name="chain1">THEN(acmp, bcmp, ccmp);</chain>
</flow>

根据定义的规则,需要定义并实现一些组件,确保SpringBoot会扫描到这些组件并注册进上下文。

import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;@Component("acmp")
public class ACmp extends NodeComponent {@Overridepublic void process() {//do your businessSystem.out.println("acmp执行");}
}

以此类推,定义另外两个组件

import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;@Component("bcmp")
public class BCmp extends NodeComponent {@Overridepublic void process() {//do your businessSystem.out.println("bcmp执行");}
}
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;@Component("ccmp")
public class CCmp extends NodeComponent {@Overridepublic void process() {//do your businessSystem.out.println("ccmp执行");}
}

更多配置项内容参考文档说明

🌿Springboot下的配置项 | LiteFlow

liteflow:#规则文件路径rule-source: config/flow.el.xml#-----------------以下非必须-----------------#liteflow是否开启,默认为trueenable: true#liteflow的banner打印是否开启,默认为trueprint-banner: true#zkNode的节点,只有使用zk作为配置源的时候才起作用,默认为/lite-flow/flowzk-node: /lite-flow/flow#上下文的最大数量槽,默认值为1024slot-size: 1024#FlowExecutor的execute2Future的线程数,默认为64main-executor-works: 64#FlowExecutor的execute2Future的自定义线程池Builder,LiteFlow提供了默认的Buildermain-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder#自定义请求ID的生成类,LiteFlow提供了默认的生成类request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator#并行节点的线程池Builder,LiteFlow提供了默认的Builderthread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder#异步线程最长的等待时间(只用于when),默认值为15000when-max-wait-time: 15000#异步线程最长的等待时间(只用于when),默认值为MILLISECONDS,毫秒when-max-wait-time-unit: MILLISECONDS#when节点全局异步线程池最大线程数,默认为16when-max-workers: 16#并行循环子项线程池最大线程数,默认为16parallelLoop-max-workers: 16#并行循环子项线程池等待队列数,默认为512parallelLoop-queue-limit: 512#并行循环子项的线程池Builder,LiteFlow提供了默认的BuilderparallelLoop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder#when节点全局异步线程池等待队列数,默认为512when-queue-limit: 512#是否在启动的时候就解析规则,默认为trueparse-on-start: true#全局重试次数,默认为0retry-count: 0#是否支持不同类型的加载方式混用,默认为falsesupport-multiple-type: false#全局默认节点执行器node-executor-class: com.yomahub.liteflow.flow.executor.DefaultNodeExecutor#是否打印执行中过程中的日志,默认为trueprint-execution-log: true#是否开启本地文件监听,默认为falseenable-monitor-file: false#是否开启快速解析模式,默认为falsefast-load: false#简易监控配置选项monitor:#监控是否开启,默认不开启enable-log: false#监控队列存储大小,默认值为200queue-limit: 200#监控一开始延迟多少执行,默认值为300000毫秒,也就是5分钟delay: 300000#监控日志打印每过多少时间执行一次,默认值为300000毫秒,也就是5分钟period: 300000

3、SpringBoot中执行LiteFlow

声明启动类,确保定义的组件扫入Spring上下文

@SpringBootApplication
//把你定义的组件扫入Spring上下文中
@ComponentScan({"com.xxx.xxx.cmp"})
public class LiteflowExampleApplication {public static void main(String[] args) {SpringApplication.run(LiteflowExampleApplication.class, args);}
}

然后可以在在Springboot任意被Spring托管的类中拿到flowExecutor,进行执行链路

这里进行单元测试

import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;@RunWith(SpringRunner.class)
@SpringBootTest(classes = RuoYiApplication.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class LiteFlowTest {@Resourceprivate FlowExecutor flowExecutor;@Testpublic void helloLiteFlow() {LiteflowResponse response = flowExecutor.execute2Resp("chain1");System.out.println(response);}
}

这里的chain1与上面规则文件中的对应。

运行结果

可以看到三个组件依次执行,这是因为配置的规则文件中配置的规则如此。

除了上面配置的普通组件之外,还可配置其他组件,比如选择组件、条件组件、循环组件等

📎普通组件 | LiteFlow

下面配置一个选择组件为例

在实际业务中,往往要通过动态的业务逻辑判断到底接下去该执行哪一个节点,这就引申出了选择节点,

选择节点可以用于SWITCH关键字中。

关于SWITCH表达式的用法,可以参考选择编排一章。

选择节点a需要继承NodeSwitchComponent。

需要实现方法processSwitch方法

import com.yomahub.liteflow.core.NodeSwitchComponent;
import org.springframework.stereotype.Component;@Component("switchCmp")
public class SwitchCmp extends NodeSwitchComponent {@Overridepublic String processSwitch() throws Exception {System.out.println("switchCmp executed!");//自己业务选择//以下代表选择了switchCmpA节点return "switchCmpA";}
}

配置规则文件

<?xml version="1.0" encoding="UTF-8"?>
<flow><chain name="chain1">THEN(acmp, bcmp, ccmp);</chain><chain name="switch_chain">SWITCH(switchCmp).to(switchCmpA, switchCmpB);</chain>
</flow>

其中switchCmpA与switchCmpB是普通组件

编写单元测试

    @Testpublic void switchTest() {LiteflowResponse response = flowExecutor.execute2Resp("switch_chain");}

运行结果

条件组件用法

LiteFlow从2.8.5版本开始,提供了条件组件的定义。

条件组件,也可以称之为IF组件,返回是一个true/false。可用于IF...ELIF...ELSE等关键字。

关于IF...ELIF...ELSE表达式的用法,可以参考条件编排这一章。

比如一个IF三元表达式,如下所示,xcmp就是IF组件,为真,执行acmp,为假,执行bcmp:

    <chain name="if_chain">IF(xcmp, acmp, bcmp);</chain>

编写条件组件

import com.yomahub.liteflow.core.NodeIfComponent;
import org.springframework.stereotype.Component;@Component("xcmp")
public class XCmp extends NodeIfComponent {@Overridepublic boolean processIf() throws Exception {//自己的业务判断return false;}
}

其它更多组件用法参考官方文档。

4、LiteFlow组件传参

在一个流程中,总会有一些初始的参数,比如订单号,用户Id等等一些的初始参数。

这时候需要通过以下方法的第二个参数传入

public LiteflowResponse execute2Resp(String chainId, Object param, Class<?>... contextBeanClazzArray)

这个流程入参,可以是任何对象,一般生产业务场景下,你可以把自己封装好的Bean传入。

编写传参组件

import com.ruoyi.system.domain.BusStudent;
import com.yomahub.liteflow.core.NodeIfComponent;
import org.springframework.stereotype.Component;@Component("xpcmp")
public class XParamCmp extends NodeIfComponent {@Overridepublic boolean processIf() throws Exception {//自己的业务判断BusStudent requestData = this.getRequestData();if(null!=requestData.getName()&&"公众号:霸道的程序猿".equals(requestData.getName())){return true;}else{return false;}}
}

传参使用

flowExecutor.execute2Resp("if_param_chain", BusStudent.builder().name("公众号:霸道的程序猿").build());

5、LiteFlow声明式组件

普通组件和条件组件,在写法上需要你自己去定义一个类去继承NodeComponent或者NodeSwitchComponent。

这样一方面造成了耦合,另一方面由于java是单继承制,所以使用者就无法再去继承自己的类了,在自由度上就少了很多玩法。

声明式组件这一特性允许你自定义的组件不继承任何类和实现任何接口,普通的类也可以依靠注解来完成LiteFlow组件的声明。

甚至于你可以用一个类去定义多个组件,仅仅依靠注解就可以完成,这个特性也叫做方法级别式声明

类级别式声明主要用处就是通过注解形式让普通的java bean变成LiteFlow的组件。无需通过继承类或者实现接口的方式。

由于LiteFlow的组件常规方式下需要继承类来定义,使得你无法再继承自己业务的类了。这个特性可以解决这个问题。

但是和常规组件一样,需要一个类对应一个组件

自定义一个组件并使用方法级别声明

import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;@LiteflowComponent("defineCmp")
@LiteflowCmpDefine
public class DefineCmp{@LiteflowMethod(LiteFlowMethodEnum.PROCESS)public void processAcmp(NodeComponent bindCmp) {System.out.println("ACmp executed!");}@LiteflowMethod(LiteFlowMethodEnum.IS_ACCESS)public boolean isAcmpAccess(NodeComponent bindCmp){return true;}@LiteflowMethod(LiteFlowMethodEnum.BEFORE_PROCESS)public void beforeAcmp(NodeComponent bindCmp){System.out.println("before A");}@LiteflowMethod(LiteFlowMethodEnum.AFTER_PROCESS)public void afterAcmp(NodeComponent bindCmp){System.out.println("after A");}@LiteflowMethod(LiteFlowMethodEnum.ON_SUCCESS)public void onAcmpSuccess(NodeComponent bindCmp){System.out.println("Acmp success");}@LiteflowMethod(LiteFlowMethodEnum.ON_ERROR)public void onAcmpError(NodeComponent bindCmp, Exception e){System.out.println("Acmp error");}@LiteflowMethod(LiteFlowMethodEnum.IS_END)public boolean isAcmpEnd(NodeComponent bindCmp) {return false;}@LiteflowMethod(value = LiteFlowMethodEnum.ROLLBACK)public void rollbackA(NodeComponent bindCmp) throws Exception {System.out.println("ACmp rollback!");}
}

同样实现效果。

6、LiteFlow还有更多功能和属性

比如EL规则的编排

🍄说明 | LiteFlow

用代码动态构造规则

🍄说明 | LiteFlow

以及各种给高级特性、平滑热更新等。

具体参考官方文档说明。

DEMO案例

滑动验证页面

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

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

相关文章

Java中的反射机制

Java中的反射机制 一、反射机制之Class1.获取Class 二、反射机制之Constructor1.获取Constructor2.使用Constructor实例化对象 三、实例化对象四、反射机制之Method1.获取Method2.调用方法&#xff08;1&#xff09;调用私有方法&#xff08;2&#xff09;调用静态方法&#xf…

【洛谷 P9240】[蓝桥杯 2023 省 B] 冶炼金属 题解(二分答案)

[蓝桥杯 2023 省 B] 冶炼金属 题目描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V V V&#xff0c; V V V 是一个正整数&#xff0c;这意味着消耗 V V V 个普通金属 O 恰好可以冶炼出一个特殊金属 X&#xff0c;当普…

【Python2】---Jmeter工具的项目实战

环境:jdk ---1.8、1.11 Jmeter的安装视频在Jmeter入门已经写过 接口自动化前置条件:接口通了----才可以进入到接口自动化不需要做功能测试,但是做自动化测试前,务必要把单接口调试通(使用Jmeter或者Postman)接口自动化流程: 测试流程----…

产业园区如何实现数字化运营管理?

​在数字化浪潮席卷全球的今天&#xff0c;产业园区正经历着前所未有的变革&#xff0c;数字化运营管理成为各个园区转型升级的发力方向&#xff0c;它不仅能够提升园区的运营管理效率&#xff0c;还能够帮助园区提高服务效能、实现精准招商、增强决策效率&#xff0c;从而全面…

Redis实战—商户查询缓存

本博客为个人学习笔记&#xff0c;学习网站&#xff1a;黑马程序员Redis入门到实战 实战篇之商户查询缓存 目录 什么是缓存 添加Redis缓存 缓存更新策略 数据库缓存不一致解决方案 案例&#xff1a;给查询商铺的缓存添加超时剔除和主动更新策略 缓存穿透 案例&#xff1…

奇富科技:大数据任务从诊断到自愈的实践之路

一、为什么要做诊断引擎 毓数平台是奇富科技公司自主研发的一站式大数据管理、开发、分析平台&#xff0c;覆盖大数据资产管理、数据开发及任务调度、自助分析及可视化、统一指标管理等多个数据生命周期流程&#xff0c;让用户使用数据的同时&#xff0c;挖掘数据最大的价值。…

打造高效、安全的交易平台:开发流程与关键要素解析

在数字化时代&#xff0c;大宗商品交易平台开发/搭建已成为连接买家与卖家的桥梁&#xff0c;为无数企业和个人提供了便捷、高效的交易机会。然而&#xff0c;随着市场的竞争日益激烈&#xff0c;如何打造一个既符合用户需求又具备竞争力的交易平台&#xff0c;成为了众多开发者…

AUTOSAR汽车电子嵌入式编程精讲300篇-基于 CAN 总线的多 ECU 通信系统设计

目录 前言 国内外研究现状 国外研究现状 国内研究现状 2 CAN 总线技术

AIGC笔记--条件自回归Transformer的搭建

1--概述 1. 自回归 TransFormer 规定Token只能看到自身及前面的Token&#xff0c;因此需生成一个符合规定的Attention Mask&#xff1b;&#xff08;代码提供了两种方式自回归Attention Mask的定义方式&#xff09;&#xff1b; 2. 使用Cross Attention实现条件模态和输入模态之…

【GIT】git合并分支

假如目前我们处于dev分支 一、重点&#xff1a;我们在开发前必须养成pull的习惯 git pull origin dev二、开发完毕后执行以下命令&#xff0c;即可将代码push到远程仓库 git add . git commit -m 提交的备注信息 git push origin dev三、此时想将dev分支合并到master分支…

文件上传{session文件包含以及条件竞争、图片文件渲染绕过(gif、png、jpg)}

session文件包含以及条件竞争 条件&#xff1a; 知道session文件存储在哪里 一般的默认位置&#xff1a; /var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID ####在没做过设置的情况下一般都是存储在/var…

【数仓】flume软件安装及配置

相关文章 【数仓】基本概念、知识普及、核心技术【数仓】数据分层概念以及相关逻辑【数仓】Hadoop软件安装及使用&#xff08;集群配置&#xff09;【数仓】Hadoop集群配置常用参数说明【数仓】zookeeper软件安装及集群配置【数仓】kafka软件安装及集群配置【数仓】flume软件安…

解决WordPress更新插件或者更新版本报WordPress 需要访问您网页服务器的权限的问题

文章目录 前言一、原因二、解决步骤总结 前言 当对WordPress的插件或者版本进行更新时报错&#xff1a;要执行请求的操作&#xff0c;WordPress 需要访问您网页服务器的权限。 请输入您的 FTP 登录凭据以继续。 如果您忘记了您的登录凭据&#xff08;如用户名、密码&#xff09…

光线追踪7 - 抗锯齿(Antialiasing)

目前为止&#xff0c;如果你放大渲染出的图像&#xff0c;可能会注意到图像边缘的明显“阶梯状”效果。这种阶梯效果通常被称为“走样”或“锯齿”。当真实相机拍摄图片时&#xff0c;边缘通常没有锯齿&#xff0c;因为边缘像素是一些前景和一些背景的混合。请考虑&#xff0c;…

5. 链接和加载(linker and loader)

链接和加载(linker and loader)&#xff1a; linker即链接器&#xff0c;它负责将多个.c编译生成的.o文件&#xff0c;链接成一个可执行文件或者是库文件&#xff1b; loader即加载器&#xff0c;它原本的功能很单一只是将可执行文件的段拷贝到编译确定的内存地址即可&#x…

英福康INFICON残余气体RGA General Chinese中文培训PPT课件

英福康INFICON残余气体RGA General Chinese中文培训PPT课件

【树上倍增】【割点】 【换根法】3067. 在带权树网络中统计可连接服务器对数目

作者推荐 视频算法专题 本文涉及知识点 树上倍增 树 图论 并集查找 换根法 深度优先 割点 LeetCode3067. 在带权树网络中统计可连接服务器对数目 给你一棵无根带权树&#xff0c;树中总共有 n 个节点&#xff0c;分别表示 n 个服务器&#xff0c;服务器从 0 到 n - 1 编号…

Java | 在消息对话框中显示文本

首先需要导入JOptionPane类&#xff0c;JOptionPane类属于Swing组件中的一种&#xff0c;其导入方式如下&#xff1a; import javax.swing.JOptionPane;可以使用JOptionPane的showMessageDialog方法显示消息文本。 参数格式&#xff1a; JOptionPane.showMessageDialog(paren…

【C语言】指针详细解读2

1.const 修饰指针 1.1 const修饰变量 变量是可以修改的&#xff0c;如果把变量的地址交给⼀个指针变量&#xff0c;通过指针变量的也可以修改这个变量。 但是如果我们希望⼀个变量加上⼀些限制&#xff0c;不能被修改&#xff0c;怎么做呢&#xff1f;这就是const的作⽤。 …

AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2024.03.01-2024.03.05

论文目录~ 1.CLEVR-POC: Reasoning-Intensive Visual Question Answering in Partially Observable Environments2.Feast Your Eyes: Mixture-of-Resolution Adaptation for Multimodal Large Language Models3.MADTP: Multimodal Alignment-Guided Dynamic Token Pruning for …