LiteFlow简介
LiteFlow是一款国产的Java轻量级流程编排和规则框架,它是为解决大型企业级项目中复杂业务流程的解耦合、规则热更新等问题而设计的。使用LiteFlow能将我们的复杂业务流程拆解成业务流程节点,并通过可热更新的DSL组合配置这些业务流程节点间的串行、并行、判断、选择等执行逻辑,这不仅能提升业务逻辑配置的灵活性,还实现了高内聚、低耦合的良好开发范式。
LiteFlow的另一个优点是非常轻量级,可以直接作为一个框架嵌入我们的Java应用程序,没有复杂的中间件依赖,当然这也意味着其功能相对简陋。这里介绍的目的并不是说一定要使用它,我们完全可以学习借鉴其中的设计思路,构建我们自己的更符合实际需要的流程编排框架。
Gitee仓库:https://gitee.com/dromara/liteFlow
官方文档:https://liteflow.cc
为什么要使用LiteFlow
对于大型业务系统项目,尤其是Java的应用领域内,业务逻辑经常是极度复杂的,就像上面这张图所示。假设图中的复杂流程是系统中的一个业务功能,这个功能由许多小的步骤共同组成,当然你最初或许还能直接通过简单的函数封装和硬编码方式来编写这些复杂的流程并通过测试和上线,但不要忘记需求是经常变化的,人员也是经常流动且水平参差不齐的,很快这段代码就会“腐烂”,当这份代码代码变成三手、四手代码后它就基本无人能看懂了,从此这个功能就成了一个功能不确定、Bug和性能问题频发、无人能维护的黑盒(这里不是说代码彻底无人能看懂了,而是看懂、重构的成本已大于项目推翻重写的成本)。
这种开发模式产出的就是典型的“面条式代码”,它会让工程的可维护性急剧下降,想要解决这个问题自然是进一步的将业务逻辑解耦合。有经验的开发人员到此通常已经会想到我们需要一个流程编排框架了,不过我们不必急着造轮子,因为LiteFlow就是这样的一个设计简洁、久经考验的框架。
LiteFlow适合以下场景:
- 业务流程极度复杂,尤其是组件编排和路由逻辑较多的大型业务系统
- 业务流程需要混合同步和异步执行,判断和选择逻辑,以及重试和并发控制等
- 需要DSL动态表达流程,且流程需要支持热更新
- 需要针对业务流程的每个节点进行统一切面和监控等
当然,这里也不是说所有场景都需要引入LiteFlow或类似框架,如果业务逻辑非常简单,我们也不必画蛇添足。此外,LiteFlow作为一个流程编排框架其主要目的之一就是解耦复杂业务逻辑,LiteFlow是非常轻量级的,它并不是一个适合于大规模数据处理的ETL框架,也不是一个完整的工作流引擎,如果你的使用场景是这些则通常有更合适的选择。
SpringBoot集成LiteFlow
LiteFlow提供了SpringBoot的起步依赖,我们直接引入即可。后续我们以SpringBoot2.7版本作为例子演示LiteFlow的使用。
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.13.2</version>
</dependency>
在工程的application.properties
配置文件中我们编写以下配置。
application.properties
# 开启LiteFlow框架
liteflow.enable=true
# 关闭工程启动时LiteFlow在控制台上打印Banner
liteflow.print-banner=false
# 流程的配置文件
liteflow.rule-source=flow.xml
配置中的liteflow.rule-source
指定了一个XML配置文件,flow.xml
需要放在Maven工程目录的src/main/resources
下,我们的流程就编写在这个配置文件中。
LiteFlow简单使用
我们这里编写一个最简单的顺序流程,stepA
、stepB
、stepC
串行的顺序执行。
flowchart TD
stepA --> stepB
stepB --> stepC
流程定义如下。
flow.xml
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(stepA, stepB, stepC);
</chain>
</flow>
其中,<flow>
定义一个流程,而<chain>
是流程片段,它的name
属性就是我们启动这个链时需要指定的名字,<flow>
可以包含一个或多个<chain>
,因为<chain>
除了作为逻辑上的入口还可以互相嵌套调用。LiteFlow也支持定义多个XML流程配置文件,通常每个流程配置代表一个复杂的业务功能,对应到配置中就是一个<flow>
定义。如果你有多个流程配置,在application.properties
中需要以逗号分隔。
liteflow.rule-source=flow1.xml,flow2.xml
在Java代码中,我们需要定义三个业务流程节点。
package com.gacfox.demo.service;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@LiteflowComponent("stepA")
public class StepA extends NodeComponent {
@Override
public void process() throws Exception {
log.info("stepA");
}
}
代码中,我们使用了@LiteflowComponent
注解并设置了节点名,这个名字需要和flow.xml
中使用的节点名对应。流程节点类需要继承NodeComponent
类并实现process()
抽象方法,这个方法中包含具体执行的业务逻辑。我们总共定义三个业务流程节点stepA
、stepB
、stepC
,其余两个也与上面代码类似,这里就不赘述了。
这里假设我们的一个Controller会触发流程的启动,启动流程代码如下。
package com.gacfox.demo.controller;
import com.gacfox.demo.common.ApiResult;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.slot.DefaultContext;
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;
@RestController
@RequestMapping("/api/v1/demo")
public class DemoController {
@Resource
private FlowExecutor flowExecutor;
@GetMapping("/startFlow")
public ApiResult<?> startFlow() {
LiteflowResponse response = flowExecutor.execute2Resp("demoChain", null, DefaultContext.class);
return ApiResult.success("流程执行结果为: " + response.isSuccess());
}
}
启动流程需要依赖注入FlowExecutor
对象,调用它的execute2Resp()
方法即可启动指定名字的流程,其中demoChain
就是我们在flow.xml
中定义的<chain>
流程名;第二个参数是流程的初始参数,我们这里没有初始参数因此传入null
;后面的参数是上下文对象,我们这里其实也尚未用到上下文数据,因此传入系统默认的DefaultContext
(其内部就是个ConcurrentHashMap
),实际开发中这个DefaultContext
其实较少使用,因为我们通常需要自定义上下文类来保存流程运行中的数据。
执行流程
此时我们触发流程执行,即可看到控制台中打印相关的日志信息。
2025-07-11 16:41:00.603 INFO 35772 --- [nio-8080-exec-1] com.yomahub.liteflow.core.FlowExecutor : [395cfe2fe48b4de88723064e0d5583f6]:requestId has generated
2025-07-11 16:41:00.603 INFO 35772 --- [nio-8080-exec-1] com.yomahub.liteflow.core.FlowExecutor : [395cfe2fe48b4de88723064e0d5583f6]:slot[0] offered
2025-07-11 16:41:00.665 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepA : [395cfe2fe48b4de88723064e0d5583f6]:[O]start component[stepA] execution
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepA : stepA
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepA : [395cfe2fe48b4de88723064e0d5583f6]:component[stepA] finished in 0 milliseconds
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepB : [395cfe2fe48b4de88723064e0d5583f6]:[O]start component[stepB] execution
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepB : stepB
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepB : [395cfe2fe48b4de88723064e0d5583f6]:component[stepB] finished in 0 milliseconds
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepC : [395cfe2fe48b4de88723064e0d5583f6]:[O]start component[stepC] execution
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepC : stepC
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.gacfox.demo.service.StepC : [395cfe2fe48b4de88723064e0d5583f6]:component[stepC] finished in 0 milliseconds
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.yomahub.liteflow.slot.Slot : [395cfe2fe48b4de88723064e0d5583f6]:CHAIN_NAME[demoChain]
stepA<0>==>stepB<0>==>stepC<0>
2025-07-11 16:41:00.666 INFO 35772 --- [nio-8080-exec-1] com.yomahub.liteflow.slot.DataBus : [395cfe2fe48b4de88723064e0d5583f6]:slot[0] released