前言

在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护的成本得就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程?几乎很难实现。

开源解决方案

说到流程引擎,开源界有大名鼎鼎的老牌开源软件JBPM,也有近几年非常流行的Activiti和Flowable。他们都是基于BPM协议,可以做到基于角色任务的流传,逻辑的流转。并且很多基于BPM协议的编辑工具都能做可视化的编辑。

但今天我要介绍的,是一款轻量级的流程编排框架——Liteflow。

Liteflow主要致力于逻辑驱动的编排。可以满足于大部分的生产业务场景。和以上著名的开源流程引擎相比,虽然不如他们那么全面,但是胜在轻量,高性能和极少的学习成本。而且这些项目都是国外开源项目,集成起来相对比较重,文档本地化也做的不够好。Liteflow拥有完善的本地文档和使用范例。能帮助你的核心系统变得更加灵活,更加易扩展。是一个解耦你系统的利器。

https://gitee.com/bryan31/liteFlow


Liteflow框架的作用

Liteflow就是为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用liteflow最合适不过。它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。

使用Liteflow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。这样,所有的组件,就能按照你的规则配置去进行复杂的流转。同时Liteflow支持规则文件的热加载,即时完成修改生效。并提供多种持久化规则的方式的扩展。

Liteflow的设计原则

Liteflow是基于工作台模式进行设计的,何谓工作台模式?

n个工人按照一定顺序围着一张工作台,按顺序各自生产零件,生产的零件最终能组装成一个机器,每个工人只需要完成自己手中零件的生产,而无需知道其他工人生产的内容。每一个工人生产所需要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的零件,也都放在工作台上。

这个模式有几个好处:

  • 每个工人无需和其他工人进行沟通。工人只需要关心自己的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。

  • 即便是工人之间调换位置,工人的工作内容和关心的资源没有任何变化。这样就保证了每个工人的稳定性。

  • 如果是指派某个工人去其他的工作台,工人的工作内容和需要的资源依旧没有任何变化,这样就做到了工人的可复用性。

  • 因为每个工人不需要和其他工人沟通,所以可以在生产任务进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产任务也能实时的被更改。这样就保证了整个生产任务的灵活性。

这个模式映射到Liteflow框架里,工人就是组件,工人坐的顺序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些特性,所以Liteflow能做到统一解耦的组件和灵活的装配。

springboot里快速配置

Liteflow支持了springboot的自动装配,当然Liteflow也为非springboot和非spring的项目也提供了支持,这里仅以springboot项目为示例进行介绍:

依赖最新的依赖包:

<dependency><groupId>com.yomahub</groupId><artifactId>liteflow-spring-boot-starter</artifactId><version>2.3.3</version>
</dependency>

配置上规则路径:

liteflow.rule-source=config/flow.xml

定义组件

Liteflow希望用户把复杂逻辑拆分成一个个可复用的组件,所以你得定义你的组件,组件的定义很简单,你需要继承NodeComponent类,然后实现process 方法就行,以下为示例:

@Component("test")
public class TestComponent extends NodeComponent {@Overridepublic void process() {Slot slot = this.getSlot();//slot为这个请求的上下文//这里为你的业务处理逻辑}
}

这里会有童鞋问,我的业务方法需要入参和出参怎么办,如何传递呢?

Liteflow为每个线程都自动分配了唯一的一个slot,可以理解为上下文。想一想上面说的那个模型,每个组件不需要和其他组件进行信息互通,所需要的参数从slot里取就是了,同时,执行完业务逻辑之后,把结果也放入slot里。所以每个组件都是独立的无参构造,这样就消除了每个组件的差异性。

这里的slot能贯穿所有组件,每一个组件都可以访问到slot里所有的数据。当然每个请求之间的slot,Liteflow做了严格的隔离,不用担心数据会串的问题。

Liteflow提供的默认Slot是一个弱类型的对象,这里建议使用者自己定义一个值对象,只需要继承AbsSlot类,便可成为你自己的Slot。更加贴合业务。

组件除了必须要实现的process 方法,还有几个可选实现:

isAccess:表示是否进入该节点,可以用于业务参数的预先判断

isContinueOnError:表示出错是否继续往下执行下一个组件,默认为false

isEnd:表示是否立即结束整个流程 ,默认为false,也可以在业务日志里根据业务判断来调用this.setIsEnd(true)来结束整个流程。

@Component("test")
public class TestComponent extends NodeComponent {@Overridepublic void process() {Slot slot = this.getSlot();//slot为这个请求的上下文//这里为你的业务处理逻辑}@Overridepublic boolean isAccess() {Slot slot = this.getSlot();//这里做你的参数检查,如果没获取到必须的业务参数,就不会进入该组件boolean checkResult = true;//模拟检查结果为truereturn checkResult;}@Overridepublic boolean isContinueOnError() {return super.isContinueOnError();//默认为false}@Overridepublic boolean isEnd() {return super.isEnd();//默认为false}
}

你只需定义你的业务组件,之后,在启动时,Liteflow会自动扫描到你定义的所有组件,并进行加载。

编辑规则文件

实现完了组件之后,你需要定义规则文件,之前规则文件的路径配置在了config/flow.xml中,所以我们要编辑这个文件。

Liteflow的规则文件定义非常简单好理解。简单的配置,但是能覆盖大部分的应用场景。

先来看一个示例:

<chain name="chain1"><then value="a,c"/> <when value="b,d"/> <then value="e,f,g"/>
</chain>

在Liteflow中,定义了then和when两种线程执行方式,then代表串行,上面的示例中,c必须要等a执行完才能执行。when代表并行,上面的示例中,b,d同时执行。并且b,d都执行完了,下面的e,f,g才能挨个顺序执行。

再来看个稍微复杂点的:

<chain name="chain1"><then value="a,c(b|d)"/> <then value="e,f,g"/>
</chain>

Liteflow提供了条件组件,这种节点的职责就是路由,根据业务逻辑来路由到b节点还是d节点。

条件组件的定义示例如下,需要去继承NodeCondComponent这个类,最终返回的b就是最终要路由到的节点

@Component("c")
public class CComponent extends NodeCondComponent {@Overridepublic String processCond() throws Exception {//你的业务逻辑return "b";}
}

Liteflow允许你编辑嵌套的流程,例子如下:

<chain name="chain1"><then value="a,c,strategy1,g"/>
</chain><chain name="strategy1"><then value="m(m1|m2|strategy2)"/>
chain><chain name="strategy2"><then value="q,p(p1|p2)"/>
chain>

在这个例子中,这3条链路是串起来执行的,在xml里,可以写你的组件id,也可以写流程id。配合之前的例子,是不是能表达的流程就更加丰富了点呢。

以上3个例子涵盖了Liteflow最主要的功能,当然Liteflow还提供一些其他的特性,比如如何进行循环执行,如何打印步骤,并且Liteflow还提供了一个简易的监控模块,用于统计你的组件执行情况。这里就不一一介绍了。具体你可以点击Liteflow的Gitee主页进行查看:

https://gitee.com/bryan31/liteFlow

示例工程

为了方便用户的使用,Liteflow在项目里提供了一个测试用例,你可以直接拿来跑:


同时作者还做了一个带简单业务的示例工程,来演示如何具体实践:

https://gitee.com/bryan31/liteflow-example

这个简单业务是一个电商场景的价格计算的案例,如何通过拆分组件来组合不同的影响价格的业务。并且这个示例工程还提供了一个简单的页面供大家进行调试:


最后

在流程编排开源上,国内一直没有特别著名的开源项目。Liteflow的体量虽然无法和业界著名的流程引擎相比,但是在某些场景,的确提供了轻量级的解决方案。并且Liteflow经过了公司生产大流量业务的考验,在稳定性和性能方面有一定保障。希望Liteflow这个开源框架能帮助到有这方面业务需要的同学们。

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

别再用硬编码写业务流程了,试试这款轻量级流程编排框架相关推荐

  1. mysql 统计_告别硬编码,mysql 如何实现按某字段的不同取值进行统计

    上周我突然意识到,我在grafana上写的 sql 语句存在多处硬编码.这篇笔记将记录如何实现没有硬编码的sql语句,以及自学编程过程中如何应对自己的笨拙代码和难题不断的状况. 1.有效但粗笨的硬编码 ...

  2. Android安全开发之浅谈密钥硬编码

    Android安全开发之浅谈密钥硬编码 作者:伊樵.呆狐@阿里聚安全 1 简介 在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码.文件中,这样做会引起很大风 ...

  3. mysql 按记录编号_告别硬编码,mysql 如何实现按某字段的不同取值进行统计

    上周我突然意识到,我在grafana上写的 sql 语句存在多处硬编码.这篇笔记将记录如何实现没有硬编码的sql语句,以及自学编程过程中如何应对自己的笨拙代码和难题不断的状况. 1.有效但粗笨的硬编码 ...

  4. 告别硬编码,MySQL 如何实现按某字段的不同取值进行统计?

    上周我突然意识到,我在grafana上写的 sql 语句存在多处硬编码.这篇笔记将记录如何实现没有硬编码的 sql 语句,以及自学编程过程中如何应对自己的笨拙代码和难题不断的状况. 1.有效但粗笨的硬 ...

  5. 视频直播推流技术(MediaCodec硬编码+libRTMP,编码器),Demo - Android

    - aac audio_codec; h264,video_codec;25 framerate 25帧; - Camera-YUV帧序列-YUV帧预处理(镜像 缩放 旋转)-编码器-H264数据 从 ...

  6. EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式

    EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式 最近在研究EasyDarwin的Push库EasyPusher,EasyPusher可以推送H264视频到 ...

  7. CVE-2022-1162 Gitlab 硬编码漏洞分析

    漏洞描述 GitLab 是一个用于仓库管理系统的开源项目,使用 Git 作为代码管理工具,可通过 Web 界面访问公开或私人项目. 在GitLab CE/EE版本14.7(14.7.7之前).14.8 ...

  8. 香橙派Pi5基于Qt5视频硬编码编译

    香橙派Pi5视频通过Qt5硬编码编译 文章目录 香橙派Pi5视频通过Qt5硬编码编译 前言 一.RKMpp和RKMpi是什么? 二.编译RKMPP 1.下载地址 2.文件结构 3.开始编译 4.编译M ...

  9. 开源规则引擎——ice:致力于解决灵活繁复的硬编码问题

    背景介绍 业务中是否写了大量的 if-else?是否受够了这些 if-else 还要经常变动? 业务中是否做了大量抽象,发现新的业务场景还是用不上? 是否各种调研规则引擎,发现不是太重就是接入或维护太 ...

最新文章

  1. pandas使用transpose函数对dataframe进行转置、将dataframe的行和列进行互换(flip the rows and columns in dataframe)
  2. PXE启动芯片出错代码表、初始化/引导/载入Bootstrap错误代码
  3. Paper:《A Unified Approach to Interpreting Model Predictions—解释模型预测的统一方法》论文解读与翻译
  4. android-DNS服务找不到
  5. 解决idea一直updating index
  6. Linux SSH登陆配置文件修改
  7. 关于查询结果插入新表中 怪哉怪哉
  8. Hadoop-2.7.3-本地模式安装-wordcount例子
  9. JavaScript 稳居第一、C# 连续下跌,调查 17000 名程序员后有了这些新发现!
  10. python100例详解-Python基础之列表常见操作经典实例详解
  11. springboot在eclipse实现热部署
  12. minecraftjava版光追_我的世界:网易版终于更新狐狸生物?Java版光追技术已开始测试?...
  13. qt 分贝毫瓦 dBm 与 功率 W 相互转换
  14. Firefox检测到潜在的安全威胁,并因blog.csdn.net要求安全连接而没有继续
  15. 谷歌中国正式宣布李开复辞去总裁一职
  16. Audio解析strategy配置文件
  17. linux下查找占空间大的文件,Linux中查找当前目录下占用空间最大的前10个文件
  18. 如何加密/弄乱C源代码
  19. 怎么选择靠谱的Java培训机构?
  20. 三大管理法则—鱼缸法则、木桶效应、热炉法则

热门文章

  1. android 360旋转动画,ANDROID——仿360手机卫士的旋转打分控件
  2. oracle通信通道的文件结尾_【移民】加拿大安省发放优才计划移民邀请函;NS省干掉特快通道直申种类的申请通道...
  3. 导出参考文献是ciw格式_使用 EndNote 9 引用参考文献
  4. python语言输入两个数_python的函数输入两个参数吗
  5. UBI文件系统和镜像的制作及分区挂载说明
  6. 【数据库题型大总结】应用题总结
  7. (王道408考研操作系统)第五章输入/输出(I/O)管理-第一节2:I/O控制器
  8. TNonblockingServer 连接管理
  9. 1266. 访问所有点的最小时间
  10. 第一章 QT Creator 简介