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

本文主要是介绍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案例

滑动验证页面

这篇关于SpringBoot中集成LiteFlow(轻量、快速、稳定可编排的组件式规则引擎)实现复杂业务解耦、动态编排、高可扩展的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/782190

相关文章

QT Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

MySQL中On duplicate key update的实现示例

《MySQL中Onduplicatekeyupdate的实现示例》ONDUPLICATEKEYUPDATE是一种MySQL的语法,它在插入新数据时,如果遇到唯一键冲突,则会执行更新操作,而不是抛... 目录1/ ON DUPLICATE KEY UPDATE的简介2/ ON DUPLICATE KEY UP

Python中Json和其他类型相互转换的实现示例

《Python中Json和其他类型相互转换的实现示例》本文介绍了在Python中使用json模块实现json数据与dict、object之间的高效转换,包括loads(),load(),dumps()... 项目中经常会用到json格式转为object对象、dict字典格式等。在此做个记录,方便后续用到该方

SpringBoot请求参数传递与接收示例详解

《SpringBoot请求参数传递与接收示例详解》本文给大家介绍SpringBoot请求参数传递与接收示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录I. 基础参数传递i.查询参数(Query Parameters)ii.路径参数(Path Va

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置