Spring Boot整合Drools规则引擎实例
1、DRools介绍
官网:https://www.drools.org/
规则引擎主要完成的就是将业务规则从代码中分离出来。
DRools一款由JBoss组织提供的基于Java语言开发的开源规则引擎,目前由 Redhat 开源的规则引擎,它是 Redhat 的 KIE Group 中的组件之一,可以比较方便的跟另一个组件 JBPM 工作流配合用于管理复杂的规则流;同时 Drools 的推理策略算法在经典 Rete 算法以及其它算法的基础上做了多个版本的增强。DRools是一个具有基于前向链接和后向链接推理的规则引擎,允许快速和可靠地评估业务规则和复杂事件处理。
关于规则引擎的说明和对比可以参考另一篇文章:规则引擎
2、DRools API开发流程
Drools API开发步骤:
获取KieServices
获取KieContainer
获取KieSession
插入Fact对象
触发规则(规则需事先编写,如DRL文件或规则表等)
关闭KieSession
//1.获取KieServices
KieServices kieServices = KieServices.get();
//2.获取Kie容器对象
KieContainer kieContainer = kieServices.getKieClasspathContainer();
//3.从kie容器对象中获取会话对象
KieSession session = kieContainer.newKieSession();
//4.创建Fact对象(事实对象)
FactExample fact = new FactExample();
fact .setTest("test");
//5.将Fact对象插入到工作内存中去
session.insert(fact);
//6.激活规则,由drools框架自动进行规则匹配,如果匹配成功,则执行规则
session.fireAllRules();
//7.关闭session
session.dispose();
2.1、规则文件编码规范(建议)
所有的规则文件(.drl)应统一放在一个规定的文件夹汇总,如:/rules文件夹
书写的每一个规则应该尽量加上注释
同一类型的对象尽量放在一个规则文件中,如所有的Student类型的对象尽量放在一个规则文件中
每个规则最好都加上salience属性,明确执行顺序
Drools默认dialect为"java",尽量避免使用dialect "mvel"
3、DRools主要概念
3.1、规则引擎的构成
working Memory(工作内存)
Rule Base(规则库)
Inference Engine(推理引擎):Pattern Matcher(匹配器)、Agenda(议程)、Execution Engine(执行引擎)
3.2、规则引擎执行过程
将初始数据(fact)输入至工作内存(working Memory)
使用匹配器(Pattern Matcher)将规则库中的规则(rule)和数据(fact)匹配,匹配成功的放入到议程(Agenda)中
如果执行规则存在冲突,即同时激活了多个规则,将冲突的规则放入冲突集合(冲突是同时匹配了多条规则,不需要自己处理,drools会自动处理,也可以通过主动声明的方式限制只命中一条规则)
解决冲突,将激活的规则按顺序放入议程(Agenda)
执行议程(Agenda)中的规则,重复2-4,直到执行完毕议程中的所有规则
3.3、规则文件
3.3.1、规则文件的构成
package:包名,package对应的不一定是真正的目录,可以任意写com.abc,同一个包下的drl文件可以相互访问
import:用于导入类或者静态方法
global:全局变量
function:自定义函数
query:查询
rule end:规则体
3.3.2、规则体(rule)的基本语法
rule "ruleName" //rule关键字,表示规则开始,参数为规则的唯一名称attributes //规则属性,是rule与when之间的参数,为可选项when //关键字,后面是规则的条件部分LHS //Left Hand Side,是规则的条件部分then //后面跟规则的结果部分RHS //是规则的结果或行为
end //表示一个规则的结束
3.3.3、规则体的属性
salience:指定规则执行的优先级,用数字表示,数字越大优先级越高。如果不设置,默认从上到下执行
dialect:指定规则使用的语言类型,java或mvel
enabled:指定规则是否启用,取值为ture或false,默认为true
date-effective:指定规则生效的时间
date-expires:指定规则失效的时间
timer:定时器,指定规则触发的时间
activation-group:激活分组,同一个组内只能有一个规则触发
agenda-group:议程分组,只有获取焦点的组中的规则才有可能触发。在java代码中获得焦点。
session.getAgenda().getAgendaGroup("agenda_group_name").setFocus;
auto-focus:自动获取焦点,一般结合agenda-group使用,取值为ture或false
no-loop:防止死循环,当规则使用update之类的函数修改了Fact对象时,使当前规则再次被激活从而导致死循环。
3.4、DRools的基本语法
运算符:> < >= <= == !=
contains:检查一个Fact对象的某个属性值是否包含一个指定的对象值
not contains:检查一个Fact对象的某个属性值是否不包含一个指定的对象值
memberOf:判断一个Fact对象的某个属性是否在一个或多个集合中
not memberOf:判断一个Fact对象的某个属性是否不在一个或多个集合中
matches:判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配
not matcher:判断一个Fact对象的属性是否不与提供的标准的Java正则表达式进行匹配
3.5、DRools内置方法
update方法:更新工作内存中的数据,并让相关的规则重新匹配。更新数据时,要注意防止陷入死循环。
insert方法:向工作内存中插入数据,并让相关的规则重新匹配。
retract方法:删除工作内存中的数据,并让相关的规则重新匹配。
3.6、DRools高级语法
3.6.1、global全局变量
global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问。可以用来为规则文件提供数据或服务。语法结构:global 对象类型 对象名称。
注意事项:如果对象类型为包装类时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。如果对象类型为集合类型或者javaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。
3.6.2、query查询
query查询提供了一种查询working memory中符合约束条件的Fact对象的简单方法。它仅包含规则文件中的LHS部分,不用指定"when"和"then"部分并且以end结束。具体语法结构如下:
query 查询的名称(可选参数)LHS
end
3.6.3、function方法
function关键字用于在规则文件中定义函数,规则体中可以调用定义的function函数。使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改。
function 返回值类型 函数名(可选参数){//逻辑代码
}
3.6.4、LHS语法
1. 复合值限制in/not in
复合值限制是指超过一种匹配值的限制条件,类似于SQL语句中的in关键字。
$s:Student(name in ("张三","李四","王五"))
$s:Student(name not in ("张三","李四","王五"))
2. 条件元素eval
eval用于规则体的LHS部分,并返回一个Boolean类型的值。语法结构:eval(表达式)
eval(1==1)
3. 条件元素not
not用于判断working memory中是否存在某个Fact对象,如果不存在则返回true,存在返回true。
not Student(age<10)
4. 条件元素exists
exists与not相反,用于判断working memory中是否存在某个Fact对象,如果存在则返回true,不存在返回true。
exists Student(age<10)
5. 规则继承
规则之间使用extends关键字进行规则部分的继承,类似于java类之间的继承。
rule "rule_1"whenStudent(age>10)thenSystem.out.println("rule_1触发");
endrule "rule_2" extends "rule_1" //继承上面的规则whenStudent(age<20) //此处虽然只有一个条件,但继承上面的条件,所以此处的条件是10<age<20thenSystem.out.println("rule_2触发");
end
3.6.5、RHS语法
RHS部分需要进行业务处理。在RHS部分Drools提供了一个内置对象,名称是drools,介绍几个drools对象的方法。
1. halt
halt方法的作用是立即终止后面所有规则的执行。
rule "rule_1"whenStudent(age>10)thenSystem.out.println("rule_1触发");drools.halt(); //后面的规则不再执行
endrule "rule_2" whenStudent(age<20) thenSystem.out.println("rule_2触发");
end
2. getWorkingMemory
getRule方法的作用是返回工作内存中的对象。
rule "rule_getWorkingMemory"whenStudent(age>10)thenSystem.out.println(drools.getWorkingMemory());
end
3.getRule
getRule方法的作用是返回规则对象。
rule "rule_getRule"whenStudent(age>10)thenSystem.out.println(drools.getRule());
end
4、Spring Boot整合DRools
实现一个产品佣金规则计算逻辑,满足项目的规则触发条件则按照相应公式计算佣金,并返回结果。
例子业务逻辑简介:
创建maven工程并配置pom.xml
创建resources/rules/settlement.drl文件
创建domainn/ProjectRule***.java实体类
编写配置类config/DroolsAutoConfiguration.java(例子做了简化)
创建ProjectService.java
具体代码如下:
构建Spring Boot基础项目,可通过:https://start.spring.io/
Maven引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.3</version></parent><groupId>com.xxx</groupId><artifactId>drools-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>drools-demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><drools.version>7.57.0.Final</drools.version></properties><dependencies>//... Spring Boot 依赖<dependency><groupId>org.drools</groupId><artifactId>drools-core</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-decisiontables</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-templates</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.kie</groupId><artifactId>kie-api</artifactId><version>${drools.version}</version></dependency></dependencies>
</project>
编写规则文件DRL
//package对应的不一定是真正的目录,可以任意写com.abc,同一个包下的drl文件可以相互访问
package com.xxx;import com.xxx.droolsdemo.domain.ProjectRuleWhenCondition
import com.xxx.droolsdemo.domain.ProjectRuleWhenValue
import com.xxx.droolsdemo.domain.ProjectRuleThenCondition
import com.xxx.droolsdemo.domain.ProjectRuleThenResult
import java.math.BigDecimal
import com.sun.javafx.binding.StringFormatter
import java.util.List
import java.util.ArrayList// TODO:function定义说明
//function 返回值类型 函数名(可选参数){
// //逻辑代码
//}function Boolean inList(List targetList, Object value){Boolean flag = false;for(Object obj : targetList){System.out.println("inList" + obj);if(obj.equals(value)){flag = true;break;}}return flag;
}rule "product rule"salience 1 //指定优先级,数值越大优先级越高,不指定的情况下由上到下执行no-loop true //防止陷入死循环when$thenCondition:ProjectRuleThenCondition();$thenResult:ProjectRuleThenResult();$whenCondition:ProjectRuleWhenCondition();$whenValue : ProjectRuleWhenValue(//inList($whenCondition.getPropertyTypes(),propertyType) && //户型propertyType memberOf $whenCondition.getPropertyTypes() &&area > 0 && area<$whenCondition.getArea() && //面积区间dealCount>=$whenCondition.getDealCount() ); //成交总套数thenif($thenCondition.getIsServiceFee()){$thenResult.setServiceFeeAmount($thenCondition.getReturnAmount().multiply($thenCondition.getReturnRatio()));}else{$thenResult.setServiceFeeAmount(new BigDecimal(10086));}System.out.println(drools.getRule().getName() +"被执行");
end;
构建实体
ProjectRuleWhenCondition:规则When条件类
ProjectRuleWhenValue:规则When Fact值类
ProjectRuleThenCondition:规则Then条件类
ProjectRuleThenResult:规则Then结果类
/*** 项目规则-When条件*/
@Data
public class ProjectRuleWhenCondition {/*** 物业类型*/private List<String> propertyTypes;/*** 面积*/private BigDecimal area;/*** 成交总套数*/private Integer dealCount;}
/*** 项目规则-When值*/
@Data
public class ProjectRuleWhenValue {/*** 物业类型*/private String propertyType;/*** 面积*/private BigDecimal area;/*** 成交总套数*/private Integer dealCount;}
/*** 项目规则-Then条件*/
@Data
public class ProjectRuleThenCondition {/*** 是否服务费*/private Boolean isServiceFee;/*** 回款金额*/private BigDecimal returnAmount;/*** 回款比率*/private BigDecimal returnRatio;}
/*** 项目规则-When结果*/
@Data
public class ProjectRuleThenResult {/*** 服务费(计算得出)*/private BigDecimal serviceFeeAmount;
}
构建ProjectService,实现触发逻辑
public class ProjectService {private KieContainer kieContainer;public ProjectService() {init();}public void reload() {init();}public void run() {//1. 构建when参数ProjectRuleWhenCondition whenCondition = new ProjectRuleWhenCondition();whenCondition.setPropertyTypes(Arrays.asList("住宅", "公寓", "别墅"));whenCondition.setArea(new BigDecimal(200));whenCondition.setDealCount(1);ProjectRuleWhenValuewhenValue = new ProjectRuleWhenValue();whenValue.setPropertyType("住宅");whenValue.setArea(new BigDecimal(80));whenValue.setUnitType("三房");whenValue.setDealCount(2);whenValue.setDealTotalAmount(new BigDecimal(5000));//2. 构建then参数ProjectRuleThenCondition thenCondition = new ProjectRuleThenCondition();thenCondition.setIsServiceFee(true);thenCondition.setReturnAmount(new BigDecimal(100000));thenCondition.setReturnRatio(new BigDecimal(0.2));ProjectRuleThenResult thenResult = new ProjectRuleThenResult();//3. 初始化KIE Session//KIE是JBoss提供的一套集中式管理API,@link:https://docs.jboss.org/drools/release/7.58.0.Final/kie-api-javadoc/index.htmlKieSession kieSession = kieContainer.newKieSession();kieSession.insert(whenCondition);kieSession.insert(whenValue);kieSession.insert(thenCondition);kieSession.insert(thenResult);//只执行一个符合条件的rule,需要配合salience优先级使用//kieSession.fireAllRules(1);int i = kieSession.fireAllRules();System.out.println("规则执行了" + i + "次,返回计算结果为" + thenResult.getServiceFeeAmount());kieSession.dispose();}@SneakyThrowsprivate void init() {KieServices kieServices = KieServices.get();KieFileSystem kieFileSystem = kieServices.newKieFileSystem();ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();Resource[] resourceArray = resourcePatternResolver.getResources("rules/**/*.drl");for (Resource file : resourceArray) {kieFileSystem.write(ResourceFactory.newClassPathResource("rules/" + file.getFilename(), "UTF-8"));}KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);kb.buildAll();KieModule kieModule = kb.getKieModule();kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());}
}
测试验证,输出结果如下
product rule被执行
规则执行了1次,返回计算结果为20000.000000000001110223024625156540423631668090820312500000
修改ProjectRuleWhenValue的值,将输出不同的结果。
参考资料
Spring Boot整合Drools规则引擎--以信用卡申请为例
DROOLS规则引擎
【Drools三】打工人学习Drools高级语法
Drools 规则引擎探究以及在 IOT 的应用
Spring Boot整合Drools规则引擎实例相关推荐
- Spring Boot整合Thymeleaf模板引擎
转载自 Spring Boot整合Thymeleaf模板引擎 什么是Thymeleaf Thymeleaf是一款用于渲染XML.XHTML.HTML5内容的模板引擎.类似Velocity,FreeMa ...
- SpringBoot整合Drools规则引擎动态生成业务规则
最近的项目中,使用的是flowable工作流来处理业务流程,但是在业务规则的配置中,是在代码中直接固定写死的,领导说这样不好,需要规则可以动态变化,可以通过页面去动态配置改变,所以就花了几天时间去研究 ...
- SpringBoot2 整合 Drools规则引擎,实现高效的业务规则
本文源码:GitHub·点这里 || GitEE·点这里 一.Drools引擎简介 1.基础简介 Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的 ...
- Spring boot整合Drools、flowable决策引擎解决方案
一.Drools:DROOLS(JBOSS RULES )具有一个易于访问企业策略.易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快.效率高.业务分析师或审核人员可以利用它轻松查看业务规则 ...
- springboot2整合drools规则引擎(kie-spring+drools-core)
What&Why Drools? Drools(JBoss Rules )的前身是Codehaus的一个开源项目叫Drools,后来纳入JBoss门下,更名为JBoss Rules,成为了JB ...
- Flink整合Drools规则引擎
业务功能:根据告警规则,从告警流中将主告警和次告警进行关联. pom maven配置: <drools.version>6.5.0.Final</drools.version> ...
- java 模板引擎_极简 Spring Boot 整合 Thymeleaf 页面模板
点击"牧码小子"关注,和众多大牛一起成长! 关注后,后台回复 java ,领取松哥为你精心准备的技术干货! 虽然现在慢慢在流行前后端分离开发,但是据松哥所了解到的,还是有一些公司在 ...
- Spring Boot 整合 FreeMarker 实例
前言 在之前的文章Spring Boot 整合 Thymeleaf中,我们学习了如何将模板 Thymeleaf 整合到 Spring Boot 中,那今天我们就来看看,另一个老牌的开源免费模板引擎 - ...
- 黑马Drools学习笔记(一)——Drools规则引擎示例概述以及SpringBoot整合示例
文章目录 1. 问题引出 2. 规则引擎概述 2.1 什么是规则引擎 2.2 使用规则引擎的优势 2.3 规则引擎应用场景 2.4 Drools介绍 3. Drools入门案例 3.1 业务场景说明 ...
最新文章
- Google Duplex语气自然流利,外媒却质疑其演示通话录音是伪造的
- python基础知识点大全-【python基础学习】基础重点难点知识汇总
- ML之SL:监督学习(Supervised Learning)的简介、应用、经典案例之详细攻略
- 看得懂的设计模式 享元模式python3 最基本(简单)实现
- IE本地网页弹出黄条“限制网页脚本”
- Python安装FrankMocap实现3D人体姿态估计
- 疲劳驾驶监测方案_【Nano Energy】TENG用于驾驶员驾驶状态监测
- spring整合hibernate出现HibernateException: Unable to get the default Bean Validation factory
- 4.9 内容代价函数
- STM32驱动LCD1602,哪位同学需要的,来了
- 产品经理面试——简历填写
- SVN 提示svn-base: 系统找不到指定的文件
- RAL 2022|基于3D语义共视图的语义SLAM精确回环检测
- 【优秀课设】基于Linux粤嵌GEC6818开发板的电子乐队程序设计(四种模式:和弦模式、键盘模式、鼓点模式、编曲模式)
- Xshell7的下载和安装
- Unparseable date: “2019-03-27“
- 部分安卓机型无法打开公众号/http链接,部分安卓机型无法打开公众号/http链接白屏
- Java对接微盟开放平台
- 嫌微信公众号排版太丑?这里让你一步到位
- 基于RFID技术的智能门禁系统设计(控制部分)
热门文章
- eclipse 或 sts 常用设置
- 联想重启乐檬?5G时代手机双品牌战略带来变局 1
- 香港买android手机,2015 Q3中国大陆/香港/台湾最热门Android手机Top 10排行榜
- 从RRT到RRT*,再到Informed RRT*,路径规划算法怎么写
- JPress企业模板-Athena
- AutoCAD标注显示图框处理
- Mac配置Java开发环境
- Redis初学笔记一
- oracle中varchar 和 nvarchar2的区别,Oracle中char,varchar,varchar2,nvarchar,nvarchar2的区别
- 提交App Store被拒