本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
关于 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 规则引擎就是这么简单,在实际的程序中能帮助我们解决很多现实问题。

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » JAVA规则引擎 Drools 教程