drools入门案例分析
今天小编给大家分享一下drools入门案例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
一、背景
最近在学习规则引擎drools
,此处简单记录一下drools
的入门案例。
1.Drools介绍
drools是一款由JBoss组织提供的基于Java语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。
二、为什么要学习drools
假设我们存在如下场景:在我们到商店购买衣服的时候,经常会发生这样的事情,购买1件不打折,购买2件打0.98折,购买3件级以上打0.85折。
那么我们在代码中如果要实现上述功能,是不是就需要编写if ... else
语句,假设后期规则变了,是不是就需要修改这些if ... else
语句,然后程序重新部署。这样是可以实现,但是不够优雅。那么我们是否可以将这些业务规则写入到规则文件中,以后规则变更直接修改规则文件即可?而drools
就可以实现这个功能。
三、实现上方这个简单的打折案例
1、引入jar包
org.drools drools-bom pom 7.69.0.Final import org.drools drools-compiler org.drools drools-mvel ch.qos.logback logback-classic 1.2.11
2、编写kmodule.xml配置文件
此配置文件需要放置在resources/META-INF
目录下。
此处我们需要关注一下 kbase
下package
的值,这个值需要和规则文件中的package
值一致,否则会找不到规则,具体看下方。
3、编写规则文件
1、规则文件的语法
包名,必须放置在第一行package// 引入Java中的类,需要些全限定名import// 定义function ,可选function // Optional// 定义 query ,可选query // Optionaldeclare // Optionalglobal // Optional// rule 关键字 "rule name" 规则的名字rule "rule name" // Attributes 属性可选 when // 关键字 // Conditions 条件,可为空 then // Actions // 匹配后执行的结果end // 关键字
2、编写规则文件
规则文件的名字无所谓,比如: book-discount.drl
// 包名,必须防止到第一行,这个名字需要和 kbase中package属性的值一致package com.huan.shop/** * 倒入类 */import com.huan.drools.CustomerOrder// 定义规则rule "shop-rule-01" when // 模式匹配:到工作内存中查找CustomerOrder,并且这个对象的purchaseQuantity值需要是1, // 如果条件成立,$order是绑定变量名,一般以$开头,和fact对象区分开 $order:CustomerOrder(purchaseQuantity == 1) then System.out.println("匹配规则 shop-rule-01"); // 赋值,此处赋值后,在Java代码中获取获取到赋值后的值 $order.setDiscount(1D);endrule "shop-rule-02" when $order:CustomerOrder(purchaseQuantity == 2) then System.out.println("匹配规则 shop-rule-02"); $order.setDiscount(0.98);endrule "shop-rule-03" when $order:CustomerOrder(purchaseQuantity >= 3) then System.out.println("匹配规则 shop-rule-03"); $order.setDiscount(0.85);end
3、解释一下包名
如果 shop-discount.drl
的包名修改为com.huan.shop1
则会提示如下警告:
12:43:01.589 [main] WARN org.drools.compiler.kie.builder.impl.KieBuilderImpl - File 'com/huan/shop/shop-discount.drl' is in folder 'com/huan/shop' but declares package 'com.huan.shop1'. It is advised to have a correspondance between package and folder names.
四、编写Java代码
1、编写一个订单对象
此对象保存的是用户购买了几件衣服和对应的折扣。
/** * 客户购买衣服的订单,省略 getter 和 setter 方法 * * @author huan.fu * @date 2022/5/12 - 11:27 */public class CustomerOrder { /** * 购买了几件衣服 */ private Integer purchaseQuantity; /** * 最终打多少折 */ private Double discount; public CustomerOrder(Integer purchaseQuantity) { this.purchaseQuantity = purchaseQuantity; }}
2、编写测试代码
1、无状态测试方法statelessSessionTest
规则规则2,即最终打0.98
折。
2、有状态测试方法statefulSessionTest
规则规则3,即最终打0.85
折。
package com.huan.drools;import org.kie.api.KieServices;import org.kie.api.event.rule.DebugRuleRuntimeEventListener;import org.kie.api.runtime.KieContainer;import org.kie.api.runtime.KieSession;import org.kie.api.runtime.StatelessKieSession;/** * drools 测试类 */public class DroolsApplication { public static void main(String[] args) throws InterruptedException { // 无状态session测试 statelessSessionTest(); // 有状态session测试 statefulSessionTest(); } private static void statelessSessionTest() { // 获取kie services KieServices kieServices = KieServices.get(); // 获取kie容器对象 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 获取kie session , 此处获取的是无状态的session,因为// 中type="stateless"就是无状态的session StatelessKieSession kieSession = kieContainer.newStatelessKieSession("shop-ksession"); // 创建一个对象,可以理解为 Fact对象,即事实对象 CustomerOrder customerOrder = new CustomerOrder(2); // 添加监听器,便于观察日志 kieSession.addEventListener(new DebugRuleRuntimeEventListener()); // 无状态的session只需要执行 execute 方法即可。 kieSession.execute(customerOrder); System.err.println("通过规则后,获取到的折扣为:" + customerOrder.getDiscount()); } private static void statefulSessionTest() { // 获取kie services KieServices kieServices = KieServices.get(); // 获取kie容器对象 KieContainer kieContainer = kieServices.getKieClasspathContainer(); // 获取kie session , 此处获取的是有状态的session KieSession kieSession = kieContainer.newKieSession("shop-ksession-stateful"); // 创建一个对象,可以理解为 Fact对象,即事实对象 CustomerOrder customerOrder = new CustomerOrder(3); // 添加监听器,便于观察日志 kieSession.addEventListener(new DebugRuleRuntimeEventListener()); // 将customerOrder对象加入到工作内存中 kieSession.insert(customerOrder); // 触发所有的规则,如果只想触发指定的规则,则使用fireAllRules(AgendaFilter agendaFilter)方法 kieSession.fireAllRules(); // 有状态的session一定需要调用dispose方法 kieSession.dispose(); System.err.println("通过规则后,获取到的折扣为:" + customerOrder.getDiscount()); }}
此处需要注意有状态session
和无状态session
写法的区别。
五、测试结果
到此,我们使用drools
实现的一个简单的案例就实现了。
六、drools引擎的基本组件
1、Rules
:我们自己定义的业务规则,比如我们自己写的规则文件。所有规则必须至少包含触发规则的条件和规则规定的操作。
2、Production memory
:规则存储在 Drools 引擎中的位置。
3、Facts
:输入或更改到 Drools 引擎中的数据,Drools 引擎匹配规则条件以执行适用规则。在规则中修改了Fact对象的值,真实的JavaBean的数据也会发生改变。
比如:当我们调用ksession.insert(对象)
,那么插入的这个对象就可以理解成Facts
对象。
4、Working memory
:facts 在 Drools 引擎中存储的位置。
5、Pattern matcher
:匹配器,将Rule Base中所有的规则与Working memory
中的Fact
对象进行模式匹配,匹配成功的规则将被激活并放入到Agenda
中。
6、Agenda
:议程,执行Agenda中被激活的排好序的规则。
以上就是"drools入门案例分析"这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。