前语

Drools是一款老牌的java规矩引擎结构,早在十几年前,我刚作业的时分,曾在一家第三方付出企业作业。在中心的付出路由层面我记得便是用Drools来做的。

难能可贵的是,Drools这个项目在十几年后还仍旧坚持着开源和更新。

github.com/kiegroup/dr…

而LiteFlow也是一款java规矩引擎,于2020年开源。经过2年的迭代,现在功用和特性也十分棒,很合适用在高复杂度的中心事务上,一起又能坚持事务的灵敏性。

gitee.com/dromara/lit…

这篇文章我们就来深化比较下这两款结构,都合适用在什么样的场景,有什么异同点,以及在相同的场景下体现力怎么。

(其间Drools依据7.6.0版别,LiteFlow依据2.9.0版别)

虽然题主便是开源项目LiteFlow的作者,可是我这几天也深化了解了下Drools,尽量从很客观的视点尝试去剖析。许多比对的成果都是依据实际运用后的感触。不过题主难免会带有一些片面的心理以及了解的片面性,尤其是Drools现在现已更新到了8.X,说实话并没有运用过。所以说的不正确的当地也请指正。

规矩引擎的界说

首先我想清晰下规矩引擎的界说,由于许多小伙伴简单把规矩引擎和流程引擎的概念混在一起。

规矩引擎一般是嵌入在应用程序组件中的,完成了将事务决策从应用程序代码中分离出来,并运用预界说的语义模块编写事务决策。承受数据输入,解释事务规矩,并依据事务规矩做出事务决策。

简略来说便是,规矩引擎首要处理易变逻辑和事务耦合的问题,规矩驱动逻辑。以前项目内写死在代码里的逻辑用规矩引擎能够提出来,随时热改动。

而流程引擎完成了将多个事务参与者之间依照某种预界说的规矩进行流通,一般需求涉及到人物信息。

简略来说便是,流程引擎首要处理事务在不同人物之间的流通问题,如请假流程,审批流程,往往要经过多个人物。规矩驱动人物流通。

两款结构的异同点

Drools和LiteFlow都是优秀的开源结构,都能把事务中的逻辑给剥离出来。并且具有自己表达式语法。

可是有所区别的是,Drools着重逻辑的片段规矩化,你能够把中心易变部分写成一个规矩文件,等同于原先写在java里的代码现在搬家到了规矩文件。规矩文件里的代码全都是能够热改动的。

而LiteFlow是依据组件式的思维规划的,更着重组件的规矩化,覆盖范围是整个事务。编列的最小单位是组件,规矩文件用来串联组件间的流通。一起LiteFlow也支撑片段式的代码规矩化,由于LiteFlow也支撑事务逻辑的脚本化。规矩支撑热改动。

所以评判一个规矩引擎是否合格的首要因素有:

  1. 有没有灵敏的规矩表达式来支撑
  2. 规矩和Java之间能否十分便利的联动
  3. API调用是否便利,和各种场景体系的集成怎么
  4. 侵入性耦合比较
  5. 规矩的学习本钱,是否简单上手
  6. 规矩表达式是否有言语插件
  7. 规矩能否和事务松耦合,存储于其他当地
  8. 规矩的改动能否实时改动逻辑
  9. 是否有界面形状来支撑非技术人员的运用
  10. 结构的功能体现

下面就从这几个方面来细细比较两款结构的体现力

规矩表达式

Drools的规矩表达式为Java量身定制的依据Charles Forgy的RETE算法的规矩引擎的完成。

Drools的规矩表达式靠近天然编程言语,具有自己的扩展名文件drl,语法支撑全,根本上天然编程言语有的语法drl全有。所以,完全能够把java的逻辑写在drl文件中。

来看下drl文件的大体姿态:

规则引擎深度对比,LiteFlow vs Drools!

能够看到,Drools界说规矩的方法是一个规矩一段,有清晰的when…then,表明当满意什么条件时,做什么。在触发规矩时分,会主动判别该去履行哪一段rule,假如满意多个条件,是能够触发多个规矩的then的。

LiteFlow编列表达式简略易懂,底层用EL表达式言语包装而成。用于组件的流通,支撑异步,挑选,条件,循环,嵌套等一些场景。

组件层面不只能够是java组件,还能够用脚本言语来编写,现在支撑了Groovy和QLExpress两种脚本言语。全部能用java完成的,用脚本言语都能够做到。

LiteFlow的规矩文件大体长这个姿态:

规则引擎深度对比,LiteFlow vs Drools!

上述LiteFlow的编列表达式中,所表达的是下面一个逻辑流:

规则引擎深度对比,LiteFlow vs Drools!

LiteFlow编列表达式支撑THEN(同步),WHEN(异步),SWITCH(挑选),IF(条件),FOR(次数循环),WHILE(条件循环)等大表达式,每个表达式又有许多扩展关键字可供选用。

脚本组件支撑的Groovy根本和java语法差不多,Groovy言语支撑的全部你均可运用。乃至能够在Groovy语法中额外界说类和方法。

定论

总的来说,两款结构都能用脚本来界说逻辑片段,在界说逻辑片段层面,Drools运用的是自研语法,LiteFlow运用的是插件式的Groovy,其实个人觉得Groovy更接近java语法,你乃至于能够在其间界说类和方法。Drools在高档应用中,也能够用规矩界说方法,可是我觉得并不那么天然。

LiteFlow最大的特点是除了界说逻辑片段外,还能够进行大局组件的编列。而这正是LiteFlow称之为编列式规矩引擎的由来。运用简略的编列语法能够规划出复杂的逻辑流。支撑java和脚本混编。

和Java的数据交换

在Drools的规矩中,你能够经过import关键字来引进java的一些类包类进行调用。

在LiteFlow的脚本组件中,Groovy也能够经过import 来引进java的任何包来调用。

Drools中,能够直接引用到fact目标。

LiteFlow中,能够直接引用到context目标,context上下文贯穿整个编列链路。

LiteFlow中,经过@ScriptBean注解,你乃至能够把spring上下文中的bean引进进来直接调用。运用这个特性,乃至于能够在脚本中调用rpc,调用数据库dao目标取数据。这个在Drools里面虽然也能够做到,可是要费事的多。

定论

根本都能满意和java的数据交换需求,可是LiteFlow在场景上支撑的明显愈加多一点。

API以及集成

在API调用层面,Drools需求去界说KieContainer,KBase,KSession一系列目标。LiteFlow结构只需求运用到LiteFlowExecutor目标。

Drools支撑了编程式接入,可是在springboot中需求自己写许多装备类往来不断集成。

LiteFlow不只支撑了编程式接入,在springboot环境下更是供给了主动装配的starer接入方法,连界说LiteFlowExecutor都不需求,直接从上下文中就能够拿到主动装配后的目标进行调用。

定论

LiteFlow api愈加简略,同Springboot集成度愈加高。

侵入性耦合比较

Drools需求在java代码里需求用到规矩的当地用KSession目标去匹配规矩进行调用。规矩和java是分离的。在调用层面耦合了KSession调用目标。

LiteFlow的规矩和java也是分离的,可是LiteFlow多了组件这一概念,所以在组件层面是需求承继的,可是一起也供给声明式组件的挑选,运用声明式的方法耦合相对要削减一些。在调用层面也需求去调用LiteFlowExecutor目标。

定论

在耦合度上面,由于LiteFlow供给编列特性,API耦合度相对稍高一些。Drools耦合少一些。

规矩的学习本钱

Drools的规矩学习本钱挺高的。由于是自研的规矩语法,需求一个很全面的了解进程。并且文档全英文。

LiteFlow的编列规矩极其简略,假如你不运用脚本组件的话,根本上10分钟即可上手。就算运用了groovy脚本,由于groovy十分类似于java,学习本钱也十分少。况且有许多的学习材料能够参阅。

LiteFlow的文档中英文完全,还有杰出的中文社区能够答疑解惑。

定论

在规矩学习本钱上,Drools的规矩学习曲线比LiteFlow高出不止一丁点。

是否有言语插件

Drools在Eclipse和IDEA上均有插件来做语法的高亮,预查看和提示。

LiteFlow在IDEA上有插件来做高亮,预查看和提示。Eclipse上没有。

定论

考虑到运用eclipse的人简直很少了,根本上2款规矩引擎在言语插件上都做到了。

规矩的存储

Drools的规矩理论上支撑你的规矩存于任何当地,但这全部都需求你手动去额外完成。自己去存,自己去取。

Drools还有款workbeanch的插件,能够将规矩存于workbeanch中。只要这个是不需求自己存取的。

LiteFlow除了本地规矩以外,原生支撑将规矩存储于任何标准SQL的数据库,还原生支撑了Nacos,Etcd,zookeeper等注册中心。只需求装备一下即可。除此之外,还供给了扩展接口,便利你自己扩展成任意的存储点。

定论

LiteFlow的规矩存储支撑比Drools丰富的多。

规矩的改动能否实时改动逻辑

Drools热改写规矩的方法现在看起来有点傻,它的规矩是经过生成jar的方法。然后体系长途动态读取jar包来完成规矩改写的。

并且一定得经过workbench的方法进行规矩的热改动。

LiteFlow在这个层面做的高档许多。假如你是用Nacos,Etcd,zookeeper等方法存储,不用做任何事,改动即主动改写。假如你是SQL数据库存储,或许本地存储。在改动规矩之后,需求调用LiteFlow结构供给的一个API进行热改动。2种方法均可热更新。并且在高并发情况下是平滑的。

定论

LiteFlow在热更新规划层面比Drools先进许多。

是否有界面形状来支撑

Drools有workbench,workbench是一个独立的插件包,供给了web界面编写规矩以及fact目标。并供给了查看和布置的才能。但由于Drools首要关怀逻辑片段,并不需求供给编列层面的拖拽UI功用,只是供给了在界面上编写规矩的才能。

LiteFlow并没有界面形状。现在只能经过第三方的Nacos,Etcd供给的界面来辅佐完成界面的规矩修改。

定论

Drools在UI形状生态上领先LiteFlow一截。

结构的功能体现

这儿用Drools和LiteFlow完成了同样的一段逻辑Demo。

依据订单金额来加积分的Demo案例。

案例逻辑很简略,依据订单的金额来动态判别该加多少积分:

小于100元,不加积分。

100到500元,加100积分。

500到1000元,加500积分。

1000元以上,加1000积分。

其间Drools的规矩如下:

package rules;
import com.example.droolsdemo.entity.Order;
rule "score_1"
when
    $order:Order(amount<100)
then
    $order.setScore(0);
    System.out.println("触发了规矩1");
end
rule "score_2"
when
    $order:Order(amount>=100 && amount < 500)
then
    $order.setScore(100);
    System.out.println("触发了规矩2");
end
rule "score_3"
when
    $order:Order(amount>=500 && amount < 1000)
then
    $order.setScore(500);
    System.out.println("触发了规矩3");
end
rule "score_4"
when
    $order:Order(amount>=1000)
then
    $order.setScore(1000);
    System.out.println("触发了规矩4");
end

其间等价的LiteFlow规矩如下:

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <nodes>
        <node id="w" type="switch_script">
            <![CDATA[
                def amount = defaultContext.getData("order").getAmount();
                if (amount < 100){
                    return "a";
                }else if(amount >= 100 && amount < 500){
                    return "b";
                }else if(amount >= 500 && amount < 1000){
                    return "c";
                }else{
                    return "d";
                }
            ]]>
        </node>
        <node id="a" type="script">
            <![CDATA[
                def order = defaultContext.getData("order");
                order.setScore(0);
                println("履行规矩a");
            ]]>
        </node>
        <node id="b" type="script">
            <![CDATA[
                def order = defaultContext.getData("order");
                order.setScore(100);
                println("履行规矩b");
            ]]>
        </node>
        <node id="c" type="script">
            <![CDATA[
                def order = defaultContext.getData("order");
                order.setScore(500);
                println("履行规矩c");
            ]]>
        </node>
        <node id="d" type="script">
            <![CDATA[
                def order = defaultContext.getData("order");
                order.setScore(1000);
                println("履行规矩d");
            ]]>
        </node>
    </nodes>
    <chain name="chain1">
        SWITCH(w).TO(a, b, c, d);
    </chain>
</flow>

两款结构都全用脚本来写的情况下,测验的进程中,去除全部的打印日志,履行10w次,得到的成果如下:

Drools 履行10w次,耗时0.7秒

LiteFlow全脚本组件履行10w次,耗时3.6秒

由于LiteFlow在全脚本组件的情况下,需求做脚本的履行和编列脚本的履行,所以花费的时间更长。

假如LiteFlow把组件更换成java,再进行履行,得到的成果如下:

LiteFlow 全Java组件履行10w次,耗时0.5秒

定论

假如LiteFlow选用全脚本的方法运转,耗时会比Drools更长。假如选用全java组件的方法运转,其功能能逾越Drools一点。

所以对于LiteFlow而言,假如你期望更高的功能,则选用java组件,假如你期望更高的灵敏性,则选用脚本组件。

其实在实际事务中,把简单更改的逻辑抽出来写成脚本组件,选用java+脚本混编的方法,是更为引荐的做法。

结语

为什么会拿Drools来作为比较,其一在题主心中,Drools一直是规矩引擎界的标杆,drools有许多理念十分值得学习。其二也是由于题主也只了解Drools,其他的结构没有很好的运用过的缘故。

可是归纳来看,作为国产规矩引擎后起之秀LiteFlow明显在规划理念,支撑度方面是要优于Drools的。编列式规矩引擎作为规矩引擎的一个新的方向,也会一直探究下去的。期望大家能多多支撑这款国产的规矩引擎。在编列方向,LiteFlow除了文中所说到的一些特性以外,还有许多其他各种各样的探究性的玩法和高档特性。是一款很值得深挖的结构。

官网地址: liteflow.yomahub.com/