What ?
Drools(JBoss Rules )具有一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。
-- 百度百科
Drools 把业务决策从代码中抽取出来,可以让我们更加灵活的去编写代码,无需在编码时仍要考虑相关的业务决策,在编码时我们只需关注输入和输出,业务决策相关都交给规则文件处理。
// 注释:第一种 /* 注释:第二种 */ rule "ruleName" attributes when LHS then RHS end
例: 购物时,如果总消费在1000元以上,则享受打8折的服务
//创建javaBean Order public class Order { // 总消费 private double totalPrice; // 折后消费 private double disCountPrice; public double getTotalPrice() { return totalPrice; } public void setTotalPrice(double totalPrice) { this.totalPrice = totalPrice; } public double getDisCountPrice() { return disCountPrice; } public void setDisCountPrice(double disCountPrice) { this.disCountPrice = disCountPrice; } }
// 规则文件编写如下 -- 手敲未验证 rule "shopping_disount" when // $order 绑定变量名,以$开始,使用其可以操作相应的Fact对象。 // $tp 绑定变量也可以用于属性上 $order:Order($tp:Price >= 1000) then $order.setDisountPrice($order.getOriginalPrice()*0.8); System.out.println("规则匹配,打八折"); end
// 测试 public void testDrools() { // 1. 获取KieService KieServices kieServices = KieServices.Factory.get(); // 2. 获取kieContainer KieContainer container = kieServices.getKieClasspathContainer(); // 3. 获取kieSession KieSession kieSession = container.newKieSession(); Order o = new Order(); o.setTotalPrice(1020); // 4. insert fact kieSession.insert(p); // 5. 触发规则 kieSession.fireAllRules(); // 6. 关闭 kieSession kieSession.dispose(); }
Object(Field[Collection/Array] contains value)
Object(Field[Collection/Array] not contains value)
Object(field memberOf value[Collection/Array])
Object(field not memberOf value[Collection/Array])
Object(field matches "正则表达式")
Object(field not matches "正则表达式")
例:测试 contains / not contains
// 为了测试比较操作符创建的javaBean public class CompareEntity { private String name; private List<String> list; public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } }
// 测试操作符 contains,其他操作符使用方法也是如此 rule "testContains" when CompareEntity(name contains "张三") CompareEntity(list contains $na:name) then System.out.println("contains - $name:"+$na); System.out.println("contains - 规则触发"); end // 测试操作符 not contains rule "testNotContains" when CompareEntity(name not contains "李四") CompareEntity(list not contains $na:name) then System.out.println("not contains - $name="+$na); System.out.println("not contains - 规则触发"); end
public void testDrools() { // 1. 获取KieService KieServices kieServices = KieServices.Factory.get(); // 2. 获取kieContainer KieContainer container = kieServices.getKieClasspathContainer(); // 3. 获取kieSession KieSession kieSession = container.newKieSession(); CompareEntity o = new CompareEntity(); o.setNames("张三"); List<String> list = new ArrayList<String>(); list.add("张三"); list.add("李四"); o.setList(list); // 4. insert fact kieSession.insert(p); // 5. 触发规则 kieSession.fireAllRules(); // 6. 关闭 kieSession kieSession.dispose(); }
注:多个规则,如果想要只触发一条规则可以使用 RuleNameEqualsAgendaFilter("规则名")实现
在规则文件的RHS部分,Drools提供了一些方法,帮助我们操作工作内存中的数据,操作完成后,工作引擎会重新进行匹配。
例: 创建Student,规则文件判断条件,使用内置方法更改年龄(age),让多个规则都匹配
public class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
rule "insertDrl" when $s:Student(age<10) then // 插入新的数据,重新匹配 Student s1 = new Student(); s1.setAge(15); insert(s1); System.out.println("age<10 规则匹配,插入新的fact,age=15"); end rule "insert2" when $s:Student(age>=10 && age<=15) then $s.setAge(25); // 更新数据 update($s); System.out.println("age>=10 && age<=15 规则触发,更新age=25"); end rule "inset3" when Student(age>=25) then System.out.println("age>=25 规则触发"); end
属性名 | 作用 |
salience | 指定规则优先级 |
dialect | 指定规则使用语言类型,java/mvel |
enabled | 指定规则是否启用 |
no-loop | 防止死循环 |
例:测试salience
// 按照优先级数值越大的先执行,未设置,按照由上到下的顺序执行。 rule "rule_1" salience 9 when eval(true) then System.out.println("规则rule_1触发"); end rule "rule_2" salience 10 when eval(true) then System.out.println("规则rule_2触发"); end rule "rule_3" salience 8 when eval(true) then System.out.println("规则rule_3触发"); end
在使用global定义的全局变量时有两点需要注意:
1、对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。
2、如果对象类型为集合类型或JavaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。
// 语法结构如下 query 查询的名称(可选参数) LHS end
例:
//不带参数的查询 //当前query用于查询Working Memory中age>10的Student对象 query "query_1" $student:Student(age > 15) end //带有参数的查询 query "query_2"(String sname) $student:Student(age > 15 && name == sname) end
public void testQuery(){ KieServices services = KieServices.Factory.get(); KieContainer container = services.getKieClasspathContainer(); KieSession kieSession = container.newKieSession(); Student s1 = new Student(); Student s2 = new Student(); Student s3 = new Student(); s1.setAge(11); s1.setName("张三"); s2.setAge(20); s2.setName("李四"); s3.setAge(25); s3.setName("王五"); kieSession.insert(s1); kieSession.insert(s2); kieSession.insert(s3); QueryResults results = kieSession.getQueryResults("query_1"); System.out.println("result.size="+results.size()); for (QueryResultsRow row:results){ Student s = (Student) row.get("$student"); System.out.println(s.getName()); } System.out.println("----------------------------------------------"); QueryResults res = kieSession.getQueryResults("query_2","张三"); System.out.println(res.size()); for (QueryResultsRow row:res){ Student s = (Student) row.get("$student"); System.out.println(s.getName()); } //关闭 kieSession.dispose(); }
function 返回值类型 函数名(可选参数){ //逻辑代码 }