1、简介
LiteFlow 是一个轻量,快速的组件式流程引擎框架 / 规则引擎,组件编排,组件复用,帮助解耦业务代码,让每一个业务片段都是一个优雅的组件,并支持热加载规则配置,实现即时修改。
1.1 规则区别
LiteFlow和Flowable不一样,LiteFlow专注于逻辑规则而Flowable是流程规则。
首先我想明确下规则引擎的定义,因为很多小伙伴容易把规则引擎和流程引擎的概念混在一起。
简单来说就是,规则引擎主要解决易变逻辑和业务耦合的问题,规则驱动逻辑。以前项目内写死在代码里的逻辑用规则引擎可以提出来,随时热变更。
而流程引擎实现了将多个业务参与者之间按照某种预定义的规则进行流转,通常需要涉及到角色信息。
简单来说就是,流程引擎主要解决业务在不同角色之间的流转问题,如请假流程,审批流程,往往要经过多个角色。规则驱动角色流转。
1.2 LiteFlow特点
LiteFlow最大的特点是除了定义逻辑片段外,还可以进行全局组件的编排。而这正是LiteFlow称之为编排式规则引擎的由来。使用简单的编排语法可以设计出复杂的逻辑流。支持java和脚本混编。
而LiteFlow是基于组件式的思想设计的,更强调组件的规则化,覆盖范围是整个业务。编排的最小单位是组件,规则文件用来串联组件间的流转。同时LiteFlow也支持片段式的代码规则化,因为LiteFlow也支持业务逻辑的脚本化。规则支持热变更。如果你是用Nacos,zookeeper等方式存储,不用做任何事,改变即自动刷新。如果你是SQL数据库存储,或者本地存储。在改变规则之后,需要调用LiteFlow框架提供的一个API进行热变更。2种方式均可热更新。并且在高并发情况下是平滑的。
LiteFlow最方便的还是和SpringBoot结合,搞JAVA的都是SpringBoot这条线讨饭吃,支持SpringBoot的工具,那就必须得盘它。
1.3 使用场景
你有想过类似以下的多线程流程编排该如何写吗?
又例如
LiteFlow适用于拥有复杂逻辑的业务,比如说价格引擎,下单流程等,这些业务往往都拥有很多步骤,这些步骤完全可以按照业务粒度拆分成一个个独立的组件,进行装配复用变更。使用LiteFlow,你会得到一个灵活度高,扩展性很强的系统。因为组件之间相互独立,也可以避免改一处而动全身的这样的风险。LiteFlow最擅长去解耦你的系统,如果你的系统业务逻辑复杂,并且实现代码臃肿不堪,那LiteFlow框架会是一个非常好的解决方案。
最重要的一点是,LiteFlow的每一个节点都是以多线程的方式执行,并且做了串行、并行的流程控制,这点性能上是可以保证每个节点都不会走像传统的串行执行链路模式老路。
1.4 不适合的场景
它不适合做角色任务之间的流转,类似于审批流,A审批完应该是B审批,然后再流转到C角色。
2、快速开始
2.1 引入依赖
以Springboot项目搭建为例
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>{latest.version}</version>
</dependency>
2.2 配置
组件的定义
在依赖了以上jar包后,你需要定义并实现一些组件,确保SpringBoot会扫描到这些组件并注册进上下文。
@Component("a")
public class ACmp extends NodeComponent {
@Override
public void process() {
System.out.println("Exec ACmp");
}
}
以此类推再分别定义b,c组件:
@Component("b")
public class BCmp extends NodeComponent {
@Override
public void process() {
System.out.println("Exec BCmp");
}
}
@Component("c")
public class CCmp extends NodeComponent {
@Override
public void process() {
System.out.println("Exec CCmp");
}
}
2.3 SpringBoot配置文件
然后,在你的SpringBoot的application.properties或者application.yml里添加配置(这里以properties为例,yaml也是一样的)
更多配置项请参考配置项章节。
liteflow.rule-source=config/**/*.el.xml
规则文件的定义
同时,你得在resources下的config/flow.el.xml
中定义规则:
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
THEN(a, b, c);
</chain>
</flow>
实例较为简单,更多表达式写法请参考规则章节。SpringBoot在启动时会自动装载规则文件。
声明启动类
@SpringBootApplication
//把你定义的组件扫入Spring上下文中
@ComponentScan({"com.xxx.xxx.cmp"})
public class LiteflowExampleApplication {
public static void main(String[] args) {
SpringApplication.run(LiteflowExampleApplication.class, args);
}
}
然后你就可以在Springboot任意被Spring托管的类中拿到flowExecutor,进行执行链路:
@Component
public class YourClass{
@Resource
private FlowExecutor flowExecutor;
public void testConfig(){
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
}
}
2.4 上线文透传
概念
在执行器执行流程时会分配数据上下文实例给这个请求。不同请求的数据上下文实例是完全隔离的。里面存放着此请求所有的用户数据。不同的组件之间是不传递参数的,所有的数据交互都是通过这个数据上下文来实现的。
意思是说,组件定义的时候就是固定的方法执行比如public void process();这个方法,里面是固定的实现,你无法进行传参进去,那正常的流程中,我执行玩这个节点,到下一个节点要根据上面的节点执行过的数据,那咋办?
所以LiteFlow设计是用线程上下文进行数据透传,一旦在数据上下文中放入数据,整个链路中的任一节点都是可以取到。
LiteFlow在新版本中支持了多上下文,在执行的时候同时初始化你传入的多个上下文。在组件里也可以根据class类型很方便的拿到。而官方也是推荐使用自己实现上下文,不要用默认的,因为默认的存在一下弱引用类型参数,无法满足实际中各个业务的使用场景。
// 上下文就是个普通的类,大部分包含两个方法,get和set值即可。
public class TestContext {
private Set<String> set = new ConcurrentHashSet<>();
public void add2Set(String str) {
set.add(str);
}
public Set<String> getSet() {
return set;
}
}
执行流程方法:
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始参数, OrderContext.class, UserContext.class, SignContext.class);
在组件之中可以这样去获得这个上下文实例:
@LiteflowComponent("yourCmpId")
public class YourCmp extends NodeComponent {
@Override
public void process() {
OrderContext orderContext = this.getContextBean(OrderContext.class);
UserContext userContext = this.getContextBean(UserContext.class);
SignContext signContext = this.getContextBean(SignContext.class);
//如果你只想获取第一个上下文,第一个上下文是OrderContext,那么也可以用这个方法
//OrderContext orderContext = this.getFirstContextBean();
...
}
}
3、性能
LiteFlow绝大部分工作都是在启动时完成,包括解析规则,注册组件,组装元信息。而执行链路时几乎对系统没有额外的消耗。官网有案例经历过双11,明星顶流带货等大流量的考验。性能的主要原因还是各自实现的业务逻辑,如果在业务逻辑中跑批耗时较大的,只能说是自身的原因,这个LiteFlow无法改善更多。
4、最后
通过上面的介绍,我们大概了解了LiteFlow的实现概念、适用场景、简易示例,如果在我们的项目中去规划是否要使用它,它是否能给项目带来合理性收益或改善,这需要和团队一起讨论,个人的经验是先用if-else实现好逻辑,再去考虑优化的事,如果一上来就用高科技,那其实带来的维护和学习成本还是挺高的。见仁见智了,下一章会讲外部存储的实现。