关于 Drools 框架很久了,一直没来得及整理这方面的资料。最近有人在微信公众号问到了我,于是我便抽了些时间,整理了这篇教程。希望能对大家有所帮助!
我们的日常生活是由规则驱动的。每次我们在开车的时候停在红灯处,之所以这样做,因为我们遵循一条规则,灯变红时我们应该停下来。如果你跳起来,最终会落到地面,这是由地球引力所决定的,它可以被表示成简单的数学方程。然而,对于我们生活日常中的规则,我们使用更加简单的结构来表示:当 XXX 的时候,做 XXX 的事。
when 满足什么样的条件 then 最终结果
在程序中普遍的存在一些业务逻辑规则。比如下面的代码:
if(){} else if(){} else{}
在这些规则不变的情况下,我们的程序能完成正常的需求规则。但是程序中的一些规则经常是需要变动的,这些变动我们可以通过代码来更改。但是往往一些需求规则变动太频繁,常改代码不是常事,因此我们需要一种更灵活的方法来实现。在这时 Drools 规则引擎框架诞生了,它能极大的方便我们更改一些程序中的规则。
Drools 简介
JBoss Rules 的前身是Codehaus的一个开源项目叫 Drools。最近被纳入JBoss门下,更名为JBoss Rules,成为了JBoss应用服务器的规则引擎。
Drools 是为 Java 量身定制的基于Charles Forgy的RETE算法的规则引擎的实现。具有了OO接口的RETE,使得商业规则有了更自然的表达。
Drools 的用 XML 的<Conditons>、<Consequence> 节点表达If–Then句式,而里面可以嵌入上述语言的代码作为判断语句和执行语句。
其中 Java 代码会使用Antlr进行解释,而 Groovy 和 Python 本身就是脚本语言,可以直接调用。
Drools 的聪明之处在于,用 XML 节点来规范 If–Then 句式和事实的定义,使引擎干起活来很舒服。
而使用 Java,Groovy等原生语言来做判断和执行语句,让程序员很容易过渡、移植,学习曲线很低。
下面我们进入实战系列,实现一个手机话费的例子。
定义规则
首先要分析自己的业务逻辑,根据业务而制定出不同的规则,这里我们假设有3个规则。
- 对于新开户的手机用户送20元话费。
- 在2014年10月到12期间充值的用户,不论金额多少充值满3次就赠送5元话费。
- 当月充值金额达到100以上,每达到一次赠送话费10元。
Drools 教程
分析这些规则,并把他们抽象成一个 EntityRule 对象。
package com.core.drools; import java.util.UUID; /** * EntityRule-Model * @author www.xttblog.com */ public class EntityRule { private String username; private boolean account; private int addtime; private double currentmoney; private double totailaddmoney; public void getSerialnumber(String username,double currentmoney){ System.out.println("Account:"+username+" Balance:¥"+currentmoney); System.out.println("Serial Number:"+UUID.randomUUID().toString()); } }
定义规则引擎
业务和规则都整理清楚了我们就可以开始规则引擎的核心部分啦,这里我定义的是接口和实现类。
package com.core.drools; /** * RuleEngine-Interface * @author www.xttblog.com */ public interface RuleEngine { public void init(); public void refresh(); public void execute(final EntityRule entityRule); }
实现规则引擎
package com.core.drools; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.drools.RuleBase; import org.drools.StatefulSession; import org.drools.compiler.DroolsParserException; import org.drools.compiler.PackageBuilder; import org.drools.rule.Package; import org.drools.spi.Activation; /** * RuleEngine-Implements * @author www.xttblog.com */ public class RuleEngineImpl implements RuleEngine{ private RuleBase ruleBase; @Override public void init() { System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm:ss"); ruleBase =SingleRuleFactory.getRuleBase(); try { PackageBuilder backageBuilder = getPackageBuilderFile(); ruleBase.addPackages(backageBuilder.getPackages()); } catch (DroolsParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } @Override public void refresh() { ruleBase = SingleRuleFactory.getRuleBase(); Package[] packages = ruleBase.getPackages(); for(Package items :packages){ ruleBase.removePackage(items.getName()); } init(); } @Override public void execute(final EntityRule entityRule) { if(null == ruleBase.getPackages() || 0 == ruleBase.getPackages().length) { return; } StatefulSession statefulSession = ruleBase.newStatefulSession(); statefulSession.insert(entityRule); statefulSession.fireAllRules(new org.drools.spi.AgendaFilter() { public boolean accept(Activation activation) { return !activation.getRule().getName(). contains("_test"); } }); statefulSession.dispose(); } private PackageBuilder getPackageBuilderFile()throws Exception { List<String> drlFilePath = getRuleFile(); List<Reader> readers = loadRuleFile(drlFilePath); PackageBuilder backageBuilder = new PackageBuilder(); for (Reader r : readers) { backageBuilder.addPackageFromDrl(r); } if(backageBuilder.hasErrors()) { throw new Exception(backageBuilder.getErrors().toString()); } return backageBuilder; } private List<Reader> loadRuleFile(List<String> drlFilePath)throws FileNotFoundException { if (null == drlFilePath || 0 == drlFilePath.size()) { return null; } List<Reader> readers = new ArrayList<Reader>(); for (String ruleFilePath : drlFilePath) { readers.add(new FileReader(new File(ruleFilePath))); } return readers; } private List<String> getRuleFile(){ List<String> drlFilePath = new ArrayList<String>(); String path="D:/utils/my/DroolsProject/src/ com/core/drools/drools_rule.drl"; drlFilePath.add(path); return drlFilePath; } }
再定义一个单例的RuleBase工厂类。
package com.core.drools; import org.drools.RuleBase; import org.drools.RuleBaseFactory; /** * @author www.xttblog.com */ public class SingleRuleFactory { private static RuleBase ruleBase; public static RuleBase getRuleBase(){ return null != ruleBase ? ruleBase : RuleBaseFactory.newRuleBase(); } }
编写规则文件
规则文件可以根据自己的业务需求定义多个文件,这里我只定义了一个。
package com.core.drools import com.core.drools.EntityRule; rule accountEntity //One salience 100 lock-on-active true when $entityRule : EntityRule(account == true) then System.out.println("The new account:Present¥20.0"); $entityRule.setCurrentmoney($entityRule.getCurrentmoney()+20); $entityRule.getSerialnumber($entityRule.getUsername(),$entityRule.getCurrentmoney()); System.out.println(); end rule billEntity //two salience 99 lock-on-active true date-effective "2014-010-01 00:00:00" date-expires "2014-012-31 23:59:59" when $entityRule : EntityRule(addtime >= 3) then System.out.println("Prepaid phone numberreach "+$entityRule.getAddtime()+" times:Present ¥"+$entityRule.getAddtime()/3*5); $entityRule.setCurrentmoney($entityRule.getCurrentmoney()+$entityRule.getAddtime()/3*5); $entityRule.getSerialnumber($entityRule.getUsername(),$entityRule.getCurrentmoney()); System.out.println(); end rule addMoney //Three salience 98 lock-on-active true when $entityRule : EntityRule(totailaddmoney >= 100) then System.out.println("The account for the month top-up totail amount is "+$entityRule.getTotailaddmoney()+":Present ¥"+(int)$entityRule.getTotailaddmoney()/100*10); $entityRule.setCurrentmoney($entityRule.getCurrentmoney()+(int)$entityRule.getTotailaddmoney()/100 * 10);$entityRule.getSerialnumber($entityRule.getUsername(),$entityRule.getCurrentmoney()); end
测试引擎
package com.test; import java.io.IOException; import com.core.drools.EntityRule; import com.core.drools.RuleEngine; import com.core.drools.RuleEngineImpl; /** * Test Drools * @author www.xttblog.com */ public class DroolsTest { public static void main(String[] args) throws IOException { RuleEngine engineImpl =new RuleEngineImpl(); engineImpl.init(); final EntityRule entityRule= new EntityRule(); entityRule.setCurrentmoney(350d); entityRule.setUsername("Candy"); entityRule.setAccount(true); entityRule.setTotailaddmoney(350d); entityRule.setAddtime(7); engineImpl.execute(entityRule); } }
测试结果
The new account:Present ¥20.0 Account:Candy Balance:¥370.0 Serial Number:0fd98593-caa2-444d-a4ff-b4001cfb3260 ------------------------------------------------------------------------------ Prepaid phone number reach 7 times:Present ¥10 Account:Candy Balance:¥380.0 Serial Number:a118b211-c28e-4035-aa60-2f417f62b2f3 ------------------------------------------------------------------------------ The account for the month top-up totail amount is 350.0: Present ¥30 Account:Candy Balance:¥410.0 Serial Number:2bfc02c2-267f-47a2-9cda-5a4196e2b7cf
Drools 规则引擎就是这么简单,在实际的程序中能帮助我们解决很多现实问题。
: » JAVA规则引擎 Drools 教程
原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/251722.html