Drools是一款老牌的java规则引擎框架,早在十几年前,我刚工作的时候,曾在一家第三方支付企业工作。在核心的支付路由层面我记得就是用Drools来做的。
难能可贵的是,Drools这个项目在十几年后还依旧保持着开源和更新。
而LiteFlow也是一款java规则引擎,于2020年开源。经过2年的迭代,现在功能和特性也非常棒,很适合用在高复杂度的核心业务上,同时又能保持业务的灵活性。
这篇文章我们就来深入比较下这两款框架,都适合用在什么样的场景,有什么异同点,以及在相同的场景下表现力如何。
(其中Drools基于7.6.0版本,LiteFlow基于2.9.0版本)
虽然题主就是开源项目LiteFlow的作者,但是我这几天也深入了解了下Drools,尽量从很客观的角度尝试去分析。很多比对的结果都是基于实际使用后的感受。不过题主难免会带有一些主观的心理以及了解的片面性,尤其是Drools现在已经更新到了8.X。
规则引擎的定义
首先我想明确下规则引擎的定义,因为很多小伙伴容易把规则引擎和流程引擎的概念混在一起。
规则引擎通常是嵌入在应用程序组件中的,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
简单来说就是,规则引擎主要解决易变逻辑和业务耦合的问题,规则驱动逻辑。以前项目内写死在代码里的逻辑用规则引擎可以提出来,随时热变更。
而流程引擎实现了将多个业务参与者之间按照某种预定义的规则进行流转,通常需要涉及到角色信息。
简单来说就是,流程引擎主要解决业务在不同角色之间的流转问题,如请假流程,审批流程,往往要经过多个角色。规则驱动角色流转。
两款框架的异同点
Drools和LiteFlow都是优秀的开源框架,都能把业务中的逻辑给剥离出来。并且拥有自己表达式语法。
但是有所区别的是,Drools强调逻辑的片段规则化,你可以把核心易变部分写成一个规则文件,等同于原先写在java里的代码现在搬迁到了规则文件。规则文件里的代码全都是可以热变更的。
而LiteFlow是基于组件式的思想设计的,更强调组件的规则化,覆盖范围是整个业务。编排的最小单位是组件,规则文件用来串联组件间的流转。同时LiteFlow也支持片段式的代码规则化,因为LiteFlow也支持业务逻辑的脚本化。规则支持热变更。
所以评判一个规则引擎是否合格的主要因素有:
- 有没有灵活的规则表达式来支持
- 规则和Java之间能否非常方便的联动
- API调用是否方便,和各种场景系统的集成如何
- 侵入性耦合比较
- 规则的学习成本,是否容易上手
- 规则表达式是否有语言插件
- 规则能否和业务松耦合,存储于其他地方
- 规则的变更能否实时改变逻辑
- 是否有界面形态来支持非技术人员的使用
- 框架的性能表现
下面就从这几个方面来细细比较两款框架的表现力
规则表达式
Drools的规则表达式为Java量身定制的基于Charles Forgy的RETE算法的规则引擎的实现。
Drools的规则表达式贴近自然编程语言,拥有自己的扩展名文件drl,语法支持全,基本上自然编程语言有的语法drl全有。所以,完全可以把java的逻辑写在drl文件中。
LiteFlow编排表达式简单易懂,底层用EL表达式语言包装而成。用于组件的流转,支持异步,选择,条件,循环,嵌套等一些场景。
组件层面不仅可以是java组件,还可以用脚本语言来编写,目前支持了Groovy和QLExpress两种脚本语言。所有能用java实现的,用脚本语言都可以做到。
脚本组件支持的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在场景上支持的显然更加多一点。