一、“规则引擎”介绍
规则引擎是由推理引擎变化而来,并不特指某个技术框架,它可以是一个系统,也可以是一个软件的适配类组件,甚至是软件本身。规则引擎主要作用是管理和执行规则,将复杂化的执行过程通过简易的规则组合拆分,通过特定的规则组合,降低业务逻辑的复杂程度和后期维护成本,同时提高其可扩展性。
二、Drools规则引擎介绍
1.背景
Drools 是用 Java 语言编写的开源规则引擎,是KIE(知识就是一切)项目的一部分,基于Charles Forgy的RETE算法的规则引擎实现。其使用 ReteOO算法执行规则。支持使用自然语言表达业务逻辑,也可以使用 Java/Groovy/Python + XML 语法编写规则。 早期的版本一般由开发人员通过开发工具插件来定义规则,目前已有Drools Workbench通过web服务提供给业务人员维护规则。 Drools 还具有以下优点:
非常活跃的社区
生态不断的完善中
JSR 94 兼容(JSR 94 是 Java Rule Engine API)
免费
Drools规则引擎基于以下抽象组件实现:
- 规则(Rules):业务规则或DMN决策。所有规则必须至少包含触发该规则的条件以及对应的操作。
- 事实(Facts):输入到规则引擎的数据,用于规则的条件的匹配。
- 生产内存(Production memory):规则引擎中规则存储的地方
- 工作内存(Working memory):规则引擎中Fact对象存储的地方。
- 议程(Agenda):用于存储被激活的规则的分类和排序的地方。
当用户或系统在Drools中添加或更新规则相关的信息时,该信息会以一个或多个事实的形式插入Drools规则引擎的工作内存中。Drools规则引擎匹配事实和存储在生产内存中规则,筛选符合执行条件的规则。对于满足条件的规则,规则引擎会在议程中激活和执行。
Drools 被分为两个主要的部分:编译和运行时。编译是将规则描述文件按 ANTLR 3 语法进行解析,对语法进行正确性的检查,然后产生一种中间结构“descr”,descr 用 AST 来描述规则。目前,Drools 支持四种规则描述文件,分别是:drl 文件、 xls 文件、brl 文件和 dsl 文件,其中,常用的描述文件是 drl 文件和 xls 文件,而 xls 文件更易于维护,更直观,更为被业务人员所理解。运行时是将 AST传到 PackageBuilder,由 PackagBuilder来产生 RuleBase,它包含了一个或多个 Package 对象。
2.应用
因为Drools主要针对于JAVA,此处主要描述JAVA开发对Drools的应用。
-
maven依赖
<dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>7.8.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>7.8.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-mvel</artifactId> <version>7.69.0.Final</version> </dependency>
- 规则文件
Drools的规则文件一般有xls、drl、dsl、brl几种,此处介绍drl(Drools Rule Language)文件类型。一套完整的规则文件内容构成如下:
package 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用 import 用于导入类或者静态方法 global 全局变量 function 自定义函数 query 查询 rule end 规则体 -
规则体是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的部分。
规则体语法结构如下:
rule "ruleName" attributes when LHS then RHS end
rule:关键字,表示规则开始,参数为规则的唯一名称。
attributes:规则属性,是rule与when之间的参数,为可选项。
when:关键字,后面跟规则的条件部分。
LHS(Left Hand Side):是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果LHS为空,则它将被视为始终为true的条件元素。
then:关键字,后面跟规则的结果部分。
RHS(Right Hand Side):是规则的后果或行动部分的通用名称。
end:关键字,表示一个规则结束。
-
使用方式
举个例子,充会员送money。
①配置Drools的kmodule.xml文件。主要是告诉Drools规则文件在哪,然后都有什么session等等属性,文件放在resource/META-INF目录下。样例如下:<?xml version="1.0" encoding="utf-8" ?> <kmodule xmlns="http://www.drools.org/xsd/kmodule"> <!-- name:指定kbase的名称,可以任意,但是需要唯一 packages:指定规则文件的目录,需要根据实际情况境写,否则无法加载到规则文件 default:指定当前kbase是否为默认 --> <kbase name="userKbase" packages="drools" default="true"> <!-- name:指定ksession名称,可以任意,但是需要唯一 default:撒定当前session是否为默认 --> <ksession name="ksession-rule" default="true"/> </kbase> </kmodule>
②规则文件如下,随便放吧,只要能跟上面的xml文件的package能对上就行。
import org.example.entity.Cus import java.math.BigDecimal rule "rule1" when $cus : Cus(money<50) then $cus.setMoney($cus.getMoney()); end rule "rule2" when $cus : Cus(money<100 && money>=50) then $cus.setMoney($cus.getMoney().add(BigDecimal.valueOf(30))); end rule "rule3" when $cus : Cus(money>=100) then $cus.setMoney($cus.getMoney().add(BigDecimal.valueOf(100))); end
③简单的调用代码
KieServices kieServices = KieServices.Factory.get(); KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer(); // session 如果相同,想要改变数据需要使用kieContainer的update方法,并在之后使用dispose KieSession kieSession = kieClasspathContainer.newKieSession(); Cus cus = new Cus(); cus.setMoney(BigDecimal.valueOf(100)); kieSession.insert(cus); kieSession.fireAllRules(); kieSession.dispose(); System.out.println(cus.getMoney());
④单元测试调用结果如下