![[Drools]JAVA规则引擎(非常好的一篇教程)_第1页](http://file3.renrendoc.com/fileroot_temp3/2022-3/6/698930de-0500-4e4a-a1e9-f993cc13a1d2/698930de-0500-4e4a-a1e9-f993cc13a1d21.gif)
![[Drools]JAVA规则引擎(非常好的一篇教程)_第2页](http://file3.renrendoc.com/fileroot_temp3/2022-3/6/698930de-0500-4e4a-a1e9-f993cc13a1d2/698930de-0500-4e4a-a1e9-f993cc13a1d22.gif)
![[Drools]JAVA规则引擎(非常好的一篇教程)_第3页](http://file3.renrendoc.com/fileroot_temp3/2022-3/6/698930de-0500-4e4a-a1e9-f993cc13a1d2/698930de-0500-4e4a-a1e9-f993cc13a1d23.gif)
![[Drools]JAVA规则引擎(非常好的一篇教程)_第4页](http://file3.renrendoc.com/fileroot_temp3/2022-3/6/698930de-0500-4e4a-a1e9-f993cc13a1d2/698930de-0500-4e4a-a1e9-f993cc13a1d24.gif)
![[Drools]JAVA规则引擎(非常好的一篇教程)_第5页](http://file3.renrendoc.com/fileroot_temp3/2022-3/6/698930de-0500-4e4a-a1e9-f993cc13a1d2/698930de-0500-4e4a-a1e9-f993cc13a1d25.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、DroolsJAVA规则引擎(非常好的一篇教程) Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效。 本文所使用的demo已上传 1、Drools语法开始语法之前首先要了解一下drools的基本工作过程,通常而言我们使用一个接口来做事情,首先要穿进去参数,其次要获取到接口的实现执行完毕后的结果,而drools也是一样的,我们需要传递进去数据,用于规则的检查,调用外部接口,同时还可能需要获取到规则执行完毕后得到的结果。在drools中,这个传递数据进去的对象,术语叫
2、 Fact对象。Fact对象是一个普通的java bean,规则中可以对当前的对象进行任何的读写操作,调用该对象提供的方法,当一个java bean插入到workingMemory中,规则使用的是原有对象的引用,规则通过对fact对象的读写,实现对应用数据的读写,对于其中的属性,需要提供getter setter访问器,规则中,可以动态的往当前workingMemory中插入删除新的fact对象。规则文件可以使用 .drl文件,也可以是xml文件,这里我们使用drl文件。规则语法:package:对一个规则文件而言,package是必须定义的,必须放在规则文件第一行。特别的是,package的
3、名字是随意的,不必必须对应物理路径,跟java的package的概念不同,这里只是逻辑上的一种区分。同样的package下定义的function和query等可以直接使用。比如:package com.drools.demo.pointimport:导入规则文件需要使用到的外部变量,这里的使用方法跟java相同,但是不同于java的是,这里的import导入的不仅仅可以是一个类,也可以是这个类中的某一个可访问的静态方法。比如:import com.drools.demo.point.PointDomain;import com.drools.demo.point.PointDomain.get
4、ById;rule:定义一个规则。rule ruleName。一个规则可以包含三个部分:属性部分:定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等。条件部分,即LHS,定义当前规则的条件,如 when Message(); 判断当前workingMemory中是否存在Message对象。结果部分,即RHS,这里可以写普通java代码,即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用。规则事例:rule name no-loop true when $message:Message(status = 0) then System.out.print
5、ln(fit); $message.setStatus(1); update($message);end上述的属性中:no-loop : 定义当前的规则是否不允许多次循环执行,默认是false,也就是当前的规则只要满足条件,可以无限次执行。什么情况下会出现一条规则执行过一次又被多次重复执行呢?drools提供了一些api,可以对当前传入workingMemory中的Fact对象进行修改或者个数的增减,比如上述的update方法,就是将当前的workingMemory中的Message类型的Fact对象进行属性更新,这种操作会触发规则的重新匹配执行,可以理解为Fact对象更新了,所以规则需要重新
6、匹配一遍,那么疑问是之前规则执行过并且修改过的那些Fact对象的属性的数据会不会被重置?结果是不会,已经修改过了就不会被重置,update之后,之前的修改都会生效。当然对Fact对象数据的修改并不是一定需要调用update才可以生效,简单的使用set方法设置就可以完成,这里类似于java的引用调用,所以何时使用update是一个需要仔细考虑的问题,一旦不慎,极有可能会造成规则的死循环。上述的no-loop true,即设置当前的规则,只执行一次,如果本身的RHS部分有update等触发规则重新执行的操作,也不要再次执行当前规则。但是其他的规则会被重新执行,岂不是也会有可能造成多次重复执行,数据
7、紊乱甚至死循环?答案是使用其他的标签限制,也是可以控制的:lock-on-active truelock-on-active true:通过这个标签,可以控制当前的规则只会被执行一次,因为一个规则的重复执行不一定是本身触发的,也可能是其他规则触发的,所以这个是no-loop的加强版。当然该标签正规的用法会有其他的标签的配合,后续提及。date-expires:设置规则的过期时间,默认的时间格式:“日-月-年”,中英文格式相同,但是写法要用各自对应的语言,比如中文:29-七月-2010,但是还是推荐使用更为精确和习惯的格式,这需要手动在java代码中设置当前系统的时间格式,后续提及。属性用法举例
8、:date-expires 2011-01-31 23:59:59 / 这里我们使用了更为习惯的时间格式date-effective:设置规则的生效时间,时间格式同上。duration:规则定时,duration 3000 3秒后执行规则salience:优先级,数值越大越先执行,这个可以控制规则的执行顺序。其他的属性可以参照相关的api文档查看具体用法,此处略。 规则的条件部分,即LHS部分:when:规则条件开始。条件可以单个,也可以多个,多个条件一次排列,比如 when eval(true) $customer:Customer() $message:Message(status=0)上
9、述罗列了三个条件,当前规则只有在这三个条件都匹配的时候才会执行RHS部分,三个条件中第一个eval(true):是一个默认的api,true 无条件执行,类似于 while(true)$message:Message(status=0) 这句话标示的:当前的workingMemory存在Message类型并且status属性的值为0的Fact对象,这个对象通常是通过外部java代码插入或者自己在前面已经执行的规则的RHS部分中insert进去的。前面的$message代表着当前条件的引用变量,在后续的条件部分和RHS部分中,可以使用当前的变量去引用符合条件的FACT对象,修改属性或者调用方法等
10、。可选,如果不需要使用,则可以不写。条件可以有组合,比如:Message(status=0 | (status > 1 && status <=100)RHS中对Fact对象private属性的操作必须使用getter和setter方法,而RHS中则必须要直接用.的方法去使用,比如 $order:Order(name=qu) $message:Message(status=0 && orders contains $order && $=qu)特别的是,如果条件全部是 &&关系,可以使用“,”来替代
11、,但是两者不能混用如果现在Fact对象中有一个List,需要判断条件,如何判断呢?看一个例子:Message int status; List<String> names;$message:Message(status=0 && names contains 网易 && names.size >= 1)上述的条件中,status必须是0,并且names列表中含有“网易”并且列表长度大于等于1contains:对比是否包含操作,操作的被包含目标可以是一个复杂对象也可以是一个简单的值。 Drools提供了十二中类型比较操作符: > >=
12、 < <= = != contains / not contains / memberOf / not memberOf /matches/ not matchesnot contains:与contains相反。memberOf:判断某个Fact属性值是否在某个集合中,与contains不同的是他被比较的对象是一个集合,而contains被比较的对象是单个值或者对象。not memberOf:正好相反。matches:正则表达式匹配,与java不同的是,不用考虑/的转义问题not matches:正好相反。 规则的结果部分当规则条件满足,则进入规则结果部分执行,结果部分可以是纯j
13、ava代码,比如:then System.out.println(OK); /会在控制台打印出okend当然也可以调用Fact的方法,比如 $message.execute();操作数据库等等一切操作。结果部分也有drools提供的方法:insert:往当前workingMemory中插入一个新的Fact对象,会触发规则的再次执行,除非使用no-loop限定;update:更新modify:修改,与update语法不同,结果都是更新操作retract:删除RHS部分除了调用Drools提供的api和Fact对象的方法,也可以调用规则文件中定义的方法,方法的定义使用 function 关键字fu
14、nction void console System.out.println(); StringUtils.getId();/ 调用外部静态方法,StringUtils必须使用import导入,getId()必须是静态方法Drools还有一个可以定义类的关键字:declare 可以再规则文件中定义一个class,使用起来跟普通java对象相似,你可以在RHS部分中new一个并且使用getter和setter方法去操作其属性。declare Address author(quzishen) / 元数据,仅用于描述信息 createTime(2011-1-24) city : String max
15、Lengh(100) postno : intend上述的是什么呢?是元数据定义,用于描述数据的数据,没什么执行含义你可以在RHS部分中使用Address address = new Address()的方法来定义一个对象。 更多的规则语法,可以参考其他互联网资料,推荐:(写的很基础,但是部分语法写的有些简单,含糊不好理解)2、Drools应用实例:现在我们模拟一个应用场景:网站伴随业务产生而进行的积分发放操作。比如支付宝信用卡还款奖励积分等。发放积分可能伴随不同的运营策略和季节性调整,发放数目和规则完全不同,如果使用硬编码的方式去伴随业务调整而修改,代码的修改、管理、优化、测试、上线将是一件
16、非常麻烦的事情,所以,将发放规则部分提取出来,交给Drools管理,可以极大程度的解决这个问题。(注意一点的是,并非所有的规则相关内容都建议使用Drools,这其中要考虑系统会运行多久,规则变更频率等一系列条件,如果你的系统只会在线上运行一周,那根本没必要选择Drools来加重你的开发成本,java硬编码的方式则将是首选)我们定义一下发放规则:积分的发放参考因素有:交易笔数、交易金额数目、信用卡还款次数、生日特别优惠等。定义规则:/ 过生日,则加10分,并且将当月交易比数翻倍后再计算积分/ 2011-01-08 - 2011-08-08每月信用卡还款3次以上,每满3笔赠送30分/ 当月购物总金
17、额100以上,每100元赠送10分/ 当月购物次数5次以上,每五次赠送50分/ 特别的,如果全部满足了要求,则额外奖励100分/ 发生退货,扣减10分/ 退货金额大于100,扣减100分在事先分析过程中,我们需要全面的考虑对于积分所需要的因素,以此整理抽象Fact对象,通过上述的假设条件,我们假设积分计算对象如下:java view plaincopy/* * 积分计算对象 * author quzishen */ public class PointDomain / 用户名 private String userName; / 是否当日生日 private boolean birthDay;
18、 / 增加积分数目 private long point; / 当月购物次数 private int buyNums; / 当月退货次数 private int backNums; / 当月购物总金额 private double buyMoney; / 当月退货总金额 private double backMondy; / 当月信用卡还款次数 private int billThisMonth; /* * 记录积分发送流水,防止重复发放 * param userName 用户名 * param type 积分发放类型 */ public void recordPointLog(String
19、userName, String type) System.out.println(增加对+userName+的类型为+type+的积分操作记录.); public String getUserName() return userName; / 其他getter setter方法省略 定义积分规则接口java view plaincopy/* * 规则接口 * author quzishen */ public interface PointRuleEngine /* * 初始化规则引擎 */ public void initEngine(); /* * 刷新规则引擎中的规则 */ publi
20、c void refreshEnginRule(); /* * 执行规则引擎 * param pointDomain 积分Fact */ public void executeRuleEngine(final PointDomain pointDomain); 规则接口实现,Drools的API很简单,可以参考相关API文档查看具体用法:java view plaincopyimport java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOExceptio
21、n; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.drools.RuleBase; import org.drools.StatefulSession; import piler.DroolsParserException; import piler.PackageBuilder; import org.drools.spi.Activation; /* * 规则接口实现类 * author quzishen */ public class PointRuleEngin
22、eImpl implements PointRuleEngine private RuleBase ruleBase; /* (non-Javadoc) * see com.drools.demo.point.PointRuleEngine#initEngine() */ public void initEngine() / 设置时间格式 System.setProperty(drools.dateformat, yyyy-MM-dd HH:mm:ss); ruleBase = RuleBaseFacatory.getRuleBase(); try PackageBuilder backage
23、Builder = getPackageBuilderFromDrlFile(); ruleBase.addPackages(backageBuilder.getPackages(); catch (DroolsParserException e) e.printStackTrace(); catch (IOException e) e.printStackTrace(); catch (Exception e) e.printStackTrace(); /* (non-Javadoc) * see com.drools.demo.point.PointRuleEngine#refreshEn
24、ginRule() */ public void refreshEnginRule() ruleBase = RuleBaseFacatory.getRuleBase(); org.drools.rule.Package packages = ruleBase.getPackages(); for(org.drools.rule.Package pg : packages) ruleBase.removePackage(pg.getName(); initEngine(); /* (non-Javadoc) * see com.drools.demo.point.PointRuleEngine
25、#executeRuleEngine(com.drools.demo.point.PointDomain) */ public void executeRuleEngine(final PointDomain pointDomain) if(null = ruleBase.getPackages() | 0 = ruleBase.getPackages().length) return; StatefulSession statefulSession = ruleBase.newStatefulSession(); statefulSession.insert(pointDomain); /
26、fire statefulSession.fireAllRules(new org.drools.spi.AgendaFilter() public boolean accept(Activation activation) return !activation.getRule().getName().contains(_test); ); statefulSession.dispose(); /* * 从Drl规则文件中读取规则 * return * throws Exception */ private PackageBuilder getPackageBuilderFromDrlFile
27、() throws Exception / 获取测试脚本文件 List<String> drlFilePath = getTestDrlFile(); / 装载测试脚本文件 List<Reader> readers = readRuleFromDrlFile(drlFilePath); PackageBuilder backageBuilder = new PackageBuilder(); for (Reader r : readers) backageBuilder.addPackageFromDrl(r); / 检查脚本是否有问题 if(backageBuilde
28、r.hasErrors() throw new Exception(backageBuilder.getErrors().toString(); return backageBuilder; /* * param drlFilePath 脚本文件路径 * return * throws FileNotFoundException */ private List<Reader> readRuleFromDrlFile(List<String> drlFilePath) throws FileNotFoundException if (null = drlFilePath
29、| 0 = drlFilePath.size() return null; List<Reader> readers = new ArrayList<Reader>(); for (String ruleFilePath : drlFilePath) readers.add(new FileReader(new File(ruleFilePath); return readers; /* * 获取测试规则文件 * * return */ private List<String> getTestDrlFile() List<String> drlF
30、ilePath = new ArrayList<String>(); drlFilePath .add(D:/workspace2/DroolsDemo/src/com/drools/demo/point/addpoint.drl); drlFilePath .add(D:/workspace2/DroolsDemo/src/com/drools/demo/point/subpoint.drl); return drlFilePath; 为了获取单实例的RuleBase,我们定义一个工厂类java view plaincopyimport org.drools.RuleBase;
31、import org.drools.RuleBaseFactory; /* * RuleBaseFacatory 单实例RuleBase生成工具 * author quzishen */ public class RuleBaseFacatory private static RuleBase ruleBase; public static RuleBase getRuleBase() return null != ruleBase ? ruleBase : RuleBaseFactory.newRuleBase(); 剩下的就是定义两个规则文件,分别用于积分发放和积分扣减addpoint.d
32、rljava view plaincopypackage com.drools.demo.point import com.drools.demo.point.PointDomain; rule birthdayPoint / 过生日,则加10分,并且将当月交易比数翻倍后再计算积分 salience 100 lock-on-active true when $pointDomain : PointDomain(birthDay = true) then $pointDomain.setPoint($pointDomain.getPoint()+10); $pointDomain.setBuyN
33、ums($pointDomain.getBuyNums()*2); $pointDomain.setBuyMoney($pointDomain.getBuyMoney()*2); $pointDomain.setBillThisMonth($pointDomain.getBillThisMonth()*2); $pointDomain.recordPointLog($pointDomain.getUserName(),birthdayPoint); end rule billThisMonthPoint / 2011-01-08 - 2011-08-08每月信用卡还款3次以上,每满3笔赠送30
34、分 salience 99 lock-on-active true date-effective 2011-01-08 23:59:59 date-expires 2011-08-08 23:59:59 when $pointDomain : PointDomain(billThisMonth >= 3) then $pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBillThisMonth()/3*30); $pointDomain.recordPointLog($pointDomain.getUserName(
35、),billThisMonthPoint); end rule buyMoneyPoint / 当月购物总金额100以上,每100元赠送10分 salience 98 lock-on-active true when $pointDomain : PointDomain(buyMoney >= 100) then $pointDomain.setPoint($pointDomain.getPoint()+ (int)$pointDomain.getBuyMoney()/100 * 10); $pointDomain.recordPointLog($pointDomain.getUserN
36、ame(),buyMoneyPoint); end rule buyNumsPoint / 当月购物次数5次以上,每五次赠送50分 salience 97 lock-on-active true when $pointDomain : PointDomain(buyNums >= 5) then $pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBuyNums()/5 * 50); $pointDomain.recordPointLog($pointDomain.getUserName(),buyNumsPoint
37、); end rule allFitPoint / 特别的,如果全部满足了要求,则额外奖励100分 salience 96 lock-on-active true when $pointDomain:PointDomain(buyNums >= 5 && billThisMonth >= 3 && buyMoney >= 100) then $pointDomain.setPoint($pointDomain.getPoint()+ 100); $pointDomain.recordPointLog($pointDomain.getUserNa
38、me(),allFitPoint); end subpoint.drljava view plaincopypackage com.drools.demo.point import com.drools.demo.point.PointDomain; rule subBackNumsPoint / 发生退货,扣减10分 salience 10 lock-on-active true when $pointDomain : PointDomain(backNums >= 1) then $pointDomain.setPoint($pointDomain.getPoint()-10); $
39、pointDomain.recordPointLog($pointDomain.getUserName(),subBackNumsPoint); end rule subBackMondyPoint / 退货金额大于100,扣减100分 salience 9 lock-on-active true when $pointDomain : PointDomain(backMondy >= 100) then $pointDomain.setPoint($pointDomain.getPoint()-10); $pointDomain.recordPointLog($pointDomain.getUserName(),subBackMondyPoint); end 测试方法:java view plaincopypublic static void main(String args) throws IOException PointRuleEngine pointRuleEngine = new PointRuleEngineImpl(); while(true) InputStream is = System.in; BufferedReader br =
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 现场处置方案编制课件
- 2025年能源行业CCS项目经济性研究报告:市场前景与投资建议
- 2025年物流行业物流园区智能化改造对物流行业行业政策法规的适应报告
- 山西省晋中市左权县2022-2023五年级上学期期中科学试题(含答案)
- 2026届贵州省贵阳市清镇北大培文学校贵州校区化学高一上期末考试试题含解析
- 2025年导游资格证专项训练试卷:导游业务与法规冲刺押题
- 2025年Python大数据处理培训试卷:实战演练与冲刺押题
- 2025年秋季初级经济师职业资格考试 经济基础知识模拟试卷及答案
- 2025年注册会计师(CPA)考试 会计科目历2025年真题解析与模拟试卷
- 江西省白鹭洲中学2026届高二化学第一学期期中学业水平测试试题含解析
- 企业信息化项目建设进度和成果汇报课件
- 高等数学期末试卷及答案
- 从0开始跨境电商-第三章-阿里巴巴国际站入门-OK
- 新能源电站远程监控系统建设方案
- 《紫藤萝瀑布》《丁香结》《好一朵木槿花》
- 2023柔性棚洞防护结构技术规程
- 河流地貌的发育 - 侵蚀地貌
- 离网光伏发电系统详解
- 广告文案写作(第二版)全套教学课件
- 《国家电网公司电力安全工作规程(配电部分)》
- 金融学黄达ppt课件9.金融市场
评论
0/150
提交评论