LiteFlow LiteFlow
首页
  • v2.16.1 (当前版本)
  • What's New

    • What' s New In LiteFlow v2.16.1?
    • What' s New In LiteFlow v2.16.0?
  • 历史版本

    • v2.15.X
    • v2.13.X
    • v2.12.X
    • v2.11.X
    • v2.10.X
    • v2.9.X
    • v2.8.X
  • 升级指南

    • 2.13.0升级指南
    • 2.12.4升级指南
    • 2.12.0升级指南
    • 升级到2.9.3说明
    • 升级到2.9.X说明
    • 升级到2.8.X说明
    • 升级到2.7.X说明
AI Agent
AI Skill
IDEA 插件
  • 答疑解惑

    • 常见问题
    • 如何理解上下文这个概念?
    • Slot是一个什么样的概念?
  • 项目与社区

    • 项目介绍
    • 项目成员
    • 更新记录
    • 参与开发
    • 加入群聊
    • 谁在使用
赞助
GitHub (opens new window)

广告采用随机轮播方式显示 ❤️成为赞助商
首页
  • v2.16.1 (当前版本)
  • What's New

    • What' s New In LiteFlow v2.16.1?
    • What' s New In LiteFlow v2.16.0?
  • 历史版本

    • v2.15.X
    • v2.13.X
    • v2.12.X
    • v2.11.X
    • v2.10.X
    • v2.9.X
    • v2.8.X
  • 升级指南

    • 2.13.0升级指南
    • 2.12.4升级指南
    • 2.12.0升级指南
    • 升级到2.9.3说明
    • 升级到2.9.X说明
    • 升级到2.8.X说明
    • 升级到2.7.X说明
AI Agent
AI Skill
IDEA 插件
  • 答疑解惑

    • 常见问题
    • 如何理解上下文这个概念?
    • Slot是一个什么样的概念?
  • 项目与社区

    • 项目介绍
    • 项目成员
    • 更新记录
    • 参与开发
    • 加入群聊
    • 谁在使用
赞助
GitHub (opens new window)
  • 🍤LiteFlow简介
  • 🍓项目特性
  • 🧁环境支持

    • ☕️JDK支持度
    • 🌿Springboot支持度
    • 🌱Spring的支持度
  • 🍟快速开始(Hello world)

    • 🍄说明
    • 🌿Springboot场景安装运行
    • 🌱Spring场景安装运行
    • 🍩Solon场景安装运行
    • 🌵其他场景安装运行
  • 🍢配置项

    • 🍄说明
    • 🌿Springboot下的配置项
    • 🌱Spring下的配置项
    • 🍩Solon下的配置项
    • 🌵其他场景代码设置配置项
  • 🔗组件

    • 🛍继承式组件

      • 📎普通组件
      • ✂️选择组件
      • ⛓布尔组件
      • 🧬次数循环组件
      • ⌛️迭代循环组件
      • 🏄LiteflowComponent
      • 🛀组件内方法覆盖和调用
    • 🎁声明式组件

      • 🥭什么叫声明式组件
      • 🧅类级别式声明
      • 🥥方法级别式声明
  • 🧩EL规则

    • 🍄说明
    • 🌴串行编排
    • 🎋并行编排
    • 🌾选择编排
    • 🌵条件编排
    • 🌳循环编排
    • 🥦异步循环模式
    • 🎃捕获异常表达式
    • 🍄与或非表达式
    • 🍁使用子流程
    • 🍂使用子变量
    • 💐复杂编排例子
    • 🍒前置和后置编排
    • 🍉组件参数语法

      • 说明
      • tag语法
      • data语法
      • bind语法
    • 🫐重试语法
    • ⏱️超时控制语法
    • 🥯链路继承
    • 🔆验证规则
    • 🌰关于注释
    • 🌻关于分号
    • 🐚组件名包装
  • 🌮上下文

    • 🍄说明
    • 🌯数据上下文的定义和使用
    • 🪶用初始化好的上下文传入
    • 🥨给上下文设置别名
    • 🥙上下文参数注入
    • 🪴用表达式获取上下文参数
  • 🛩执行器

    • 🍄说明
    • 🎡执行方法
    • 🎢流程入参
    • 🎈LiteflowResponse对象
    • 🪃直接执行EL规则
  • 🍋脚本组件

    • 🌭脚本语言介绍
    • 🍫脚本语言种类

      • ☕️Java脚本引擎
      • 🥏Groovy脚本引擎
      • 🧀Javascript脚本引擎
      • 🥞QLExpress脚本引擎
      • 🍧Python脚本引擎
      • 🍝Lua脚本引擎
      • 🥐Aviator脚本引擎
      • 🥠Kotlin脚本引擎
    • 🍣脚本与Java进行交互
    • 🍱多脚本语言混合共存
    • 🌯文件脚本的定义
    • 🍘动态刷新脚本
    • 🍦验证脚本
    • 🗑卸载脚本
  • 🗂规则配置源

    • 📕本地规则文件配置
    • 📘SQL数据库配置源(旧)
    • 📗ZK规则文件配置源(旧)
    • 📋Nacos配置源(旧)
    • 🗄Etcd配置源(旧)
    • 📜Apollo配置源(旧)
    • 📑Redis配置源(旧)

      • 配置说明
      • 轮询模式配置
      • 订阅模式配置
    • 📙自定义配置源
  • 🏦Rule-DB模式

    • 🏦Rule-DB是什么
    • 🐬快速开始(SQL)
    • 🐘快速开始(PostgreSQL)
    • 🍃快速开始(MongoDB)
    • 📕快速开始(Redis)
    • 📗快速开始(ZooKeeper)
    • 🗄快速开始(Etcd)
    • 📋快速开始(Nacos)
    • 🧪示例工程(Demo)
      • 模块一览
      • 跑起来
      • 一个模块只有四个文件
        • 1. pom:starter + 一个后端 + 脚本插件
        • 2. application.yml:配置真的只有几行
        • 3. PublisherConfig:把Publisher交给Spring管
        • 4. RuleInitRunner:启动时灌一份初始规则
      • 三个实验,把Rule-DB的核心机制走一遍
      • 页面背后的三个接口
      • demo踩过的坑,都写在注释里
      • 接下来看什么
    • 🍢配置项参考
    • 🗃存储结构参考
    • 📤发布API与写入规范
    • ⚖️一致性与收敛模型
    • 🪁内存与性能
    • 🔭可观测性与降级
    • 🚧限制与迁移
  • 🍼元数据管理

    • ⛰元数据操作器
    • 🍖平滑热刷新
    • 🍮启动不检查规则
    • 🥨启动不检查脚本
  • 🌌异步中的线程池

    • 💧说明
    • 🐋FlowExecutor层面的线程池
    • 🐠组件异步层面的线程池
    • 🪶虚拟线程
  • 🎲动态构造

    • 🍄说明
    • 🥜构造Node
    • 🌰构造EL
    • 🍞构造Chain
  • 🧮决策路由

    • 🏖概念以及介绍
    • 🍽决策路由用法
  • 😸生命周期

    • 🐮启动时生命周期
    • 🐳执行时生命周期
  • 🎨高级特性

    • 🍌本地规则文件监听
    • 🥠组件降级
    • 🍑组件别名
    • 🥝组件事件回调
    • 🐋组件回滚
    • 🥑隐式子流程
    • 🫐活跃规则保活策略
    • 🍕私有投递
    • 🍪组件切面
    • 🍡步骤信息
    • 🧊异常
    • 🧇打印信息详解
    • 🧁自定义请求Id
    • 🫕快速解析模式
    • 🌭不同格式规则加载
    • 🍿自定义组件执行器
    • 🍥简单监控
    • 🧉XML的DTD
  • 📈指标监控

    • 📈指标监控概述
    • 🚀快速接入
    • 📋指标目录
    • 🔌Actuator端点说明
    • 📐分位与直方图
    • 🔍常用PromQL与告警
    • ⚡性能影响与基数控制
  • ⛱测试用例以及示例

    • 🪁测试用例
    • 🪀DEMO案例
  • 🪂性能表现
  • v2.16.X文档
  • 🏦Rule-DB模式
铂赛东
2026-08-07
目录

🧪示例工程(Demo)

版本支持:v2.16.1+

前面八篇快速开始是按后端拆开讲的,每一篇都只给了配置片段。如果你想直接跑起来看效果,我们准备了一个覆盖全部七个后端的示例工程:

liteflow-rule-db-demo (opens new window)

这个工程是一个Maven聚合工程,九个子模块各自对应一种后端形态。每个模块都是一个能独立启动的Spring Boot应用,自带一个网页,页面上可以直接发布规则、发布脚本、执行链路,把发布之后各节点秒级收敛这件事亲眼看一遍。

页面上的三块正好对应Rule-DB的三个动作:publishChain发布EL、publishScript发布脚本、FlowExecutor执行。结果区会把executeStep打出来,改完规则再执行一次,执行链路的变化立刻就能看见。

# 模块一览

模块 端口 后端 变更感知
demo-sql-mysql 8081 MySQL 8.0(13306) 轮询
demo-redis-single 8082 Redis 7 单点(16379) 轮询
demo-redis-sentinel 8083 Redis 7 哨兵,1主2从3哨兵(26379-26381) 轮询
demo-redis-cluster 8084 Redis 集群,6节点(17000-17005) 轮询
demo-etcd 8085 etcd 3.5(12379) watch
demo-zk 8086 ZooKeeper 3.9(12181) watch
demo-postgresql 8087 PostgreSQL 16(15432) 轮询
demo-mongodb 8088 MongoDB 7 单节点副本集(27018) 轮询
demo-nacos 8089 Nacos 2.5.3 standalone(18848) Listener推送

端口都做了偏移,不会和你本机已有的中间件撞上。九个模块各带一份只含自己所需中间件的docker-compose.yml,互不干扰,想跑哪个起哪个。

# 跑起来

前置只要JDK 21、Maven 3.8+和Docker(Compose v2)。以demo-sql-mysql为例:

# 1. 启动中间件(在模块目录下)
cd demo-sql-mysql
docker compose up -d --wait

# 2. 构建并启动(回到根目录)
cd ..
mvn -pl demo-sql-mysql -am package -DskipTests
java -jar demo-sql-mysql/target/demo-sql-mysql-1.0.0.jar

# 3. 打开页面
open http://localhost:8081/

其余模块把模块名和端口换掉即可。用完在对应模块目录下docker compose down。

demo-redis-sentinel要先生成.env

哨兵模块的compose依赖宿主机LAN IP,首次运行前先在根目录执行bash scripts/gen-env.sh,它会把HOST_IP写进根目录和demo-redis-sentinel/两份.env。换了网络环境(LAN IP变了)要重跑一次并重建容器。其余八个模块不涉及.env。

# 一个模块只有四个文件

这是这个demo最值得看的地方。剥掉页面和docker,接入Rule-DB真正要写的东西只有四处,九个模块的结构完全一样,换后端只换其中两处。

# 1. pom:starter + 一个后端 + 脚本插件

<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-rule-db-sql</artifactId>
</dependency>
<!-- 要发布脚本才需要,只发布普通chain可以不引 -->
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-script-javax-pro</artifactId>
</dependency>

换后端就是把liteflow-rule-db-sql换成-redis、-zk、-etcd、-postgresql、-mongodb、-nacos。同一时刻classpath上只能有一个后端模块,多了启动会直接报错。

# 2. application.yml:配置真的只有几行

spring:
  application:
    name: demo-sql-mysql   # 这就是Rule-DB的隔离名
  datasource:
    url: jdbc:mysql://127.0.0.1:13306/liteflow_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: root123456

liteflow:
  rule-db:
    enabled: true
    sql:
      auto-init-table: true   # 开发期让插件建表
    sync:
      poll-seconds: 2         # demo调快到2秒,方便看收敛
      reconcile-seconds: 60

DataSource没有指名,插件按类型从容器里取走唯一那个就用了,连接池沿用Spring Boot的。四张表由auto-init-table建。轮询周期默认3秒,demo调成2秒纯粹是为了页面上少等一会儿。

对照着看几个后端的配置差异,比看文档表格直观:

# redis 单点
liteflow.rule-db.redis.address: redis://127.0.0.1:16379

# redis 哨兵:地址填哨兵,外加 master-name
liteflow.rule-db.redis.address: redis://127.0.0.1:26379,redis://127.0.0.1:26380,redis://127.0.0.1:26381
liteflow.rule-db.redis.master-name: mymaster

# redis 集群:必须配 key-hash-tag
liteflow.rule-db.redis.address: redis://127.0.0.1:17000,...,redis://127.0.0.1:17005
liteflow.rule-db.redis.key-hash-tag: lf

# zk / etcd / nacos:一行连接地址
liteflow.rule-db.zk.connect-string: 127.0.0.1:12181
liteflow.rule-db.etcd.endpoints: http://127.0.0.1:12379
liteflow.rule-db.nacos.server-addr: 127.0.0.1:18848

# 3. PublisherConfig:把Publisher交给Spring管

RulePublisher是写入端,和执行端FlowExecutor是两条独立的路。demo把它声明成一个bean,destroyMethod = "close"让Spring负责关:

@Configuration
public class PublisherConfig {

    @Bean(destroyMethod = "close")
    public RulePublisher rulePublisher(DataSource dataSource,
                                       @Value("${spring.application.name}") String applicationName) {
        SqlPublisherConfig config = SqlPublisherConfig.builder()
                .applicationName(applicationName)   // 必须和执行端解析出的隔离名一致
                .dataSource(dataSource)             // 复用连接池,不要用 url
                .build();
        return RulePublisherFactory.create(config);
    }
}

九个模块唯一的差别就是这里的XxxPublisherConfig:SQL/PostgreSQL传dataSource,Redis传address,Mongo传uri和database,zk传connectString,etcd传endpoints,Nacos传serverAddr。applicationName统一从spring.application.name取,这样天然就和执行端对上了——这一项配错是最常见的坑,规则发布进去了但执行端读不到。

# 4. RuleInitRunner:启动时灌一份初始规则

demo用CommandLineRunner在启动时发布两个Java脚本和一条链路,省得你打开页面还得先手动造数据:

@Component
public class RuleInitRunner implements CommandLineRunner {

    private final RulePublisher rulePublisher;

    @Override
    public void run(String... args) {
        rulePublisher.publishScript(PublishScriptRequest.builder()
                .nodeId("s1").name("脚本s1").type("script").language("java")
                .script(S1_SCRIPT).build());
        rulePublisher.publishScript(PublishScriptRequest.builder()
                .nodeId("s2").name("脚本s2").type("script").language("java")
                .script(S2_SCRIPT).build());
        rulePublisher.publishChain(PublishChainRequest.builder()
                .chainId("demo_chain").el("THEN(s1, s2);").build());
    }
}

S1_SCRIPT是一段完整的Java类源码,这是javax-pro脚本的写法,注意它是extends NodeComponent的完整类,不是表达式片段:

import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;

public class S1 extends NodeComponent {

    @Override
    public void process() {
        DefaultContext context = this.getFirstContextBean();
        Object requestData = this.getRequestData();
        System.out.println("[s1] receive requestData: " + requestData);
        context.setData("s1Result", "s1 handled: " + requestData);
    }
}

s2则从上下文里把s1Result读出来再往下传,这样一条链路跑完你能从executeStep和上下文两个角度确认数据确实流过去了。

Publisher的调用是幂等的UPSERT,重启应用会让版本号继续加一,不会报冲突。想要"仅当不存在时创建"的语义,就加.expectedVersion(0L)。

# 三个实验,把Rule-DB的核心机制走一遍

页面开着,按顺序做这三件事,Rule-DB的运行模型基本就清楚了。

实验一:改EL,不重启。 把第1块的EL从THEN(s1, s2);改成THEN(s2, s1);,点发布规则,等两秒(etcd/zk/nacos不用等),到第3块点执行。executeStep的顺序跟着变了,应用一次没重启。这就是"存储是权威源"的意思——EL改了,执行端下一次执行会拿到新版本。

实验二:加一个脚本节点。 第2块默认给了一段s3的源码,点发布脚本,再把EL改成THEN(s1, s2, s3);发布一次,然后执行。控制台会打出[s3] requestData: ...。整个过程没有编译、没有打包、没有发版——新节点是运行期从存储里懒加载并编译出来的。

实验三:故意写错,看它什么时候失败。 把EL改成THEN(s1, s2, s99);发布,注意发布是成功的。失败发生在你点执行的那一刻,报的是找不到s99。这正是文档里那句"Publisher只校验请求字段和存储约束,发布时不会编译EL"的实际表现。这一点很关键:Rule-DB不替你做EL的语义校验,引用了不存在的组件、子chain或脚本节点,要到执行端首次编译这条chain时才暴露。所以管理后台该有的发布前校验,得自己加。

顺手还能验证一下懒加载:应用启动日志里不会有解析全量规则的动作,第一次执行demo_chain才回源拉EL和脚本并编译,第二次执行就命中缓存了,热路径上没有远程调用。

# 页面背后的三个接口

如果你要写自己的管理后台,直接照抄DemoController就行,它把Rule-DB写入端的全部用法压在了一百行里:

接口 请求体 对应API
POST /api/publish/chain {"chainId":"demo_chain","el":"THEN(s1, s2);"} rulePublisher.publishChain(...)
POST /api/publish/script {"nodeId":"s3","name":"脚本s3","type":"script","script":"<java源码>"} rulePublisher.publishScript(...)
POST /api/execute {"chainId":"demo_chain","requestData":"hello"} flowExecutor.execute2Resp(...)

type可选script、boolean_script、switch_script、for_script,对应脚本节点在EL里的四种用法。完整的字段约束、版本号语义和乐观锁用法见发布API与写入规范。

管理后台不需要拉起FlowExecutor

RulePublisher只依赖后端模块那个jar,不需要LiteFlow执行期。demo把发布端和执行端放在同一个进程里纯粹是为了一个页面能演示完,真实项目里管理后台和业务应用通常是分开部署的,两边靠applicationName这个隔离名对上。

# demo踩过的坑,都写在注释里

这九个模块是真连本地docker起的中间件,过程中撞到的环境问题都留在了compose文件和README里。几个和LiteFlow配置直接相关的:

  • Redis集群必须配key-hash-tag。Rule-DB的键要落在同一个slot上,不配这一项在集群模式下会报CROSSSLOT。demo里用的是lf。
  • MongoDB必须以副本集运行。MongoRuleRepository的读写走ClientSession.withTransaction,standalone不支持事务,会报Transaction numbers are only allowed on a replica set member or mongos。demo的compose用--replSet rs0起,并用一个一次性容器执行rs.initiate,等选出PRIMARY才退出。
  • MongoDB模块排除了MongoAutoConfiguration。否则Spring Boot会自动建一个连默认27017的MongoClient bean,而MongoConnectionManager按类型借用容器里的bean,从而绕过liteflow.rule-db.mongodb.uri,连到一个不存在的端口上。用Spring Data Mongo的项目要注意这个借用关系,多个同类bean时请显式指名。
  • Nacos必须映射gRPC端口。nacos-client 2.x同时用HTTP(8848)和gRPC(9848/9849),compose里漏掉任一个gRPC端口,客户端会因长连接建不起来报Client not connected, current status: STARTING,发布和监听都不可用。

其余的Redis哨兵网络announce、etcd镜像归档、macOS端口占用这些纯环境问题,README里有完整说明,不影响你理解Rule-DB本身。

版本

demo的父pom把liteflow.version定在2.16.1。如果你在自己的工程里遇到rule-db配javax-pro脚本时报ScriptLoadException: script for node[x] is not loaded,请升级到2.16.1.1,那是一个针对Rule-DB启动阶段初始化钩子的修复版本。

# 接下来看什么

  • 挑一个后端照着配:SQL、PostgreSQL、MongoDB、Redis、ZooKeeper、Etcd、Nacos
  • 写管理后台:发布API与写入规范
  • 上生产前:一致性与收敛模型、内存与性能、可观测性与降级、限制与迁移
帮助我们改善此文档 (opens new window)
上次更新: 2026/08/07, 23:39:56
📋快速开始(Nacos)
🍢配置项参考

← 📋快速开始(Nacos) 🍢配置项参考→

Theme by Vdoing | Copyright © 2020-2026 铂赛东 | MIT License
沪ICP备18012955号-2