liteflow学习一

简介: liteflow学习一

liteflow的业务逻辑编排能力是非常强,同时也是非常好用的。支持很多种方式的编排,串行编排、并行编排、选择编排、条件编排、循环编排,同时支持使用子流程、使用子变量等等。本文参考liteflow官网,学习liteflow的执行流程,官网对学习liteflow非常友好。

liteflow的开源地址:https://gitee.com/dromara/liteFlow,很感谢作者铂赛东开源这么好用的业务编排框架。

一、liteflow的使用

首先引入liteflow的spring-boot-starter依赖,然后继承 NodeComponent,重写process方法。在application.yml中配置xml中配置资源规则,以说明当前串行器的执行顺序。

比如当前的执行顺序是a->b->c

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="chain1">
        THEN(a, b, c);
    </chain>
</flow>

在业务系统的业务逻辑层注入FlowExecutor,chain1在业务逻辑执行对应的业务逻辑,也即这个顺序是a->b->c,也即 NodeComponent中的业务逻辑,Bean对应@Component("a")、@Component("b")、@Component("c")。

@Component
public class YourClass{
    @Resource
    private FlowExecutor flowExecutor;
    public void testConfig(){
        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
    }
}

完成编写后,即可执行,执行的顺序a->b->c串行编排。也即执行后可以看到我们想要的结果。

这样简化了我们组装业务逻辑的方式。

这么方便使用,是不是非常好奇怎么实现的呢?

二、如何实现

首先我们还是从example开始,从最基础的builder开始学习。


在脚本中,串行器以THEN开头,而并行器以WHEN开头。

@Test
    public void testBuilder() throws Exception {
        // 基于liteflowNode构建器创建节点
        LiteFlowNodeBuilder.createNode()
            .setId("a")
            .setName("组件A")
            .setType(NodeTypeEnum.COMMON)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.ACmp")
            .build();
        LiteFlowNodeBuilder.createNode()
            .setId("b")
            .setName("组件B")
            .setType(NodeTypeEnum.COMMON)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.BCmp")
            .build();
        LiteFlowNodeBuilder.createNode()
            .setId("c")
            .setName("组件C")
            .setType(NodeTypeEnum.COMMON)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.CCmp")
            .build();
        LiteFlowNodeBuilder.createNode()
            .setId("d")
            .setName("组件D")
            .setType(NodeTypeEnum.COMMON)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.DCmp")
            .build();
        LiteFlowNodeBuilder.createNode()
            .setId("e")
            .setName("组件E")
            .setType(NodeTypeEnum.SWITCH)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.ECmp")
            .build();
        LiteFlowNodeBuilder.createNode()
            .setId("f")
            .setName("组件F")
            .setType(NodeTypeEnum.COMMON)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.FCmp")
            .build();
        LiteFlowNodeBuilder.createNode()
            .setId("g")
            .setName("组件G")
            .setType(NodeTypeEnum.COMMON)
            .setClazz("com.yomahub.liteflow.test.builder.cmp1.GCmp")
            .build();
        // 创建节点后,创建chain链路
        LiteFlowChainELBuilder.createChain().setChainName("chain2").setEL("THEN(c, d)").build();
        // 创建链路
        LiteFlowChainELBuilder.createChain()
            .setChainName("chain1")
            .setEL("THEN(a, b, WHEN(SWITCH(e).to(f, g, chain2)))")
            .build();
        // 基于流程执行器执行链路1
        LiteflowResponse response = flowExecutor.execute2Resp("chain1");
        Assertions.assertTrue(response.isSuccess());
        Assertions.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getExecuteStepStr());
    }

flowExecutor.execute2Resp("chain1")这个方法是业务逻辑执行的核心方法。但是在此之前会执行一些的方法:

1)LiteFlowNodeBuilder创建a到g组件节点。从代码中可以看到节点信息最终会添加到FlowBus中,使用了FlowBus.addNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getClazz())。

2)LiteFlowChainELBuilder.createChain()创建chain的过程build中可以看到最终将数据也添加到了Chain中之外,还将chain添加到了chainMap中。

3)完成后,通过流程执行器完成请求 flowExecutor.execute2Resp("chain1")。

根据debug的信息,可以看到LiteflowExecutorInit实现了InitializingBean,重写afterPropertiesSet方法,此时会对flowExecutor做一次初始化,执行初始化Cmp,对应ruleResource进行判断,如果LiteflowConfig不存在配置信息,则加载SPI中,通过类加载器获取,如果存在,则加载,同时放入到liteflowConfig中,否则进行返回。

也即此时执行单元测试基于 flowExecutor.execute2Resp("chain1")进行执行后续的逻辑,也即3)中的方法,也即在这里完成所有的主体逻辑。

主体的逻辑整体在:

com.yomahub.liteflow.core.FlowExecutor#doExecute

这个方法里面。

因此我们对3)进行着重查看和说明。

三、chain.execute(slotIndex)的实现

//获取chain,根据chainId获取
    Chain chain = null;
    try {
        chain = FlowBus.getChain(chainId);
        if (ObjectUtil.isNull(chain)) {
            String errorMsg = StrUtil.format("couldn't find chain with the id[{}]", chainId);
            throw new ChainNotFoundException(errorMsg);
        }
        // 执行chain,也即设置槽id 对应chainId
        chain.execute(slotIndex);
    }

1)从chain到node的过程

可以看到首先会拿到chain,因为之前我们在2)完成了chain数据的填充,将将chain数据放入到了chainMap中。因此此时必然可以拿到chain的信息,然后基于chain调用节点执行器执行操作chain.execute(slotIndex)。Condition执行condition操作。当前所在的ChainName 如果对于子流程来说,那这个就是子流程所在的Chain。可以看到此时的executeCondition会执行对应的condition对应的chain。这里以串行器为例子进行说明,因此此时会进入到ThenCondition中。可以看到ThenConditon的executeCondition中存在前置preCondition.execute(slotIndex)、具体的处理executableItem.execute(slotIndex)、finally处理finallyCondition.execute(slotIndex)。此时可以看到对应的方法有三个:chain、condition、node。可以看到此时会执行节点node操作,因为前两者已经执行过。

2)node执行逻辑

设置槽索引和引用节点。,如果当前的实例可以access,则获取节点执行器,然后执行节点执行器。来到我们的执行器入口方法com.yomahub.liteflow.flow.executor.NodeExecutor#execute。这个方法可以看到,分为前置、执行中、后置方法。作者想得非常的周到,留下了扩展。除此之外,作者还给我们设置了失败重试的方法。节点组件的核心方法com.yomahub.liteflow.core.NodeComponent#execute。

在这个方法里面,会创建cmpStep对象,然后设置tag、step的信息。然后执行前置、具体的业务逻辑处理self.process(),此时会业务系统的组件方法中,也即我们自己业务系统写的NodeComponent方法,执行完成会执行成功的回调方法,如果出现异常,则设置step信息,然后执行失败回调方法。最终进行后置方法设置时间消耗。将指标统计信息添加到monitorBus中。

3)执行顺序与test中的设置对应关系

也即从这里可以看到首先会执行chain.execute(slotIndex)->executableItem.execute(slotIndex)->NodeComponent#execute,也即先执行chain,然后chain到对应的condition,最终到对应的node。也即应证了上面设置的顺序。先节点,然后condition,最终到chain。

四、实现的逻辑,可以总结如下UML


参考:https://gitee.com/dromara/liteFlow

          https://liteflow.cc/


目录
相关文章
|
存储 缓存 JavaScript
国内开源规则引擎牛起来
国内开源规则引擎牛起来
1953 0
|
设计模式 前端开发 关系型数据库
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例) 3
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例)
6483 2
|
9月前
|
存储 缓存 监控
从GC日志小白到分析大神:GCEasy实战全攻略
GCEasy是Java GC日志分析利器,支持多种垃圾收集器,通过可视化报表与智能诊断,帮助开发者快速定位内存泄漏、GC频繁等问题。本文结合实战案例,详解其原理、使用方法及性能优化策略,提升系统稳定性与并发能力。
1332 1
|
10月前
|
人工智能 JSON Java
AI时代,我们为何重写规则引擎?—— QLExpress4 重构之路
AI时代下,规则引擎的需求反而更旺盛。QLExpress4 通过全面重构,在性能、可观测性和AI友好性上大幅提升。
2576 15
AI时代,我们为何重写规则引擎?—— QLExpress4 重构之路
|
人工智能 边缘计算 5G
5G时代,别让能耗成为“隐形杀手”——聊聊5G网络的能耗管理
5G时代,别让能耗成为“隐形杀手”——聊聊5G网络的能耗管理
978 13
|
存储 人工智能 Java
Spring AI与DeepSeek实战四:系统API调用
在AI应用开发中,工具调用是增强大模型能力的核心技术,通过让模型与外部API或工具交互,可实现实时信息检索(如天气查询、新闻获取)、系统操作(如创建任务、发送邮件)等功能;本文结合Spring AI与大模型,演示如何通过Tool Calling实现系统API调用,同时处理多轮对话中的会话记忆。
3120 57
|
人工智能 数据可视化 JavaScript
颠覆开发效率!国内首个微服务编排框架Juggle开源啦!
Juggle是国内首个开源的微服务编排框架,专注于解决企业微服务进程中接口重复开发、系统对接复杂等问题。它提供零代码、低代码和AI增强功能,通过可视化拖拽快速组装简单API为复杂接口,支持多协议、多语言脚本和流程多版本管理。相比国外框架如Conductor,Juggle更贴合国内需求,具备高效开发、企业级可靠性及信创适配等优势,助力企业实现敏捷创新与数字化转型。
1331 0
颠覆开发效率!国内首个微服务编排框架Juggle开源啦!
|
JavaScript 前端开发 网络协议
WebSocket在Java Spring Boot+Vue框架中实现消息推送功能
在现代Web应用中,实时消息提醒是一项非常重要的功能,能够极大地提升用户体验。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为实现实时消息提醒提供了高效且低延迟的解决方案。本文将详细介绍如何在Java Spring Boot后端和Vue前端框架中利用WebSocket实现消息提醒功能。
2449 127
|
XML 存储 Java
万字+40张图带你探秘小而美的规则引擎框架LiteFlow
在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护的成本就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程,几乎很难实现。
|
安全 Java 编译器
springboot 整合表达式计算引擎 Aviator 使用示例详解
本文详细介绍了Google Aviator 这款高性能、轻量级的 Java 表达式求值引擎
2632 6