博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Drools(BRMS) 速成教程(上)
阅读量:4950 次
发布时间:2019-06-11

本文共 6951 字,大约阅读时间需要 23 分钟。

大家在日常开发中,肯定遇到过一些业务规则变来变去的需求,比如:会员积分系统(今天要新注册会员送10积分,明天要改成注册送优惠券,后天搞活动要改成注册自动变成高级会员...),此类需求,一般都是通过写if分支来实现的,参考下面:

if (规则条件1){   //处理1}else if (规则条件2){   //处理2}else if (规则条件3){   //处理3}...

这种代码毫无营养,而且很枯燥,有没有办法,将业务规则从代码中抽离出来,以后规则变了,不用改代码,只改规则配置就行?

今天要介绍的,可以很好的解决此类问题,Drools是一个业务规则管理的开源框架,现在归到旗下,本文将介绍一些基本的用法,方便大家快速上手。

一、添加依赖项

6.5.0.Final
1.18.2
org.drools
drools-compiler
${drools.version}
org.projectlombok
lombok
${lombok.version}

注:不同版本的drools,api有较大差异,本文采用6.5.0.Final版本,其它版本的用法请自行参考官方文档。(lombok是可选的,建议加上,简化java代码书写)

 

二、新建一个演示用的pojo类Message

package com.cnblogs.yjmyzz.drools.demo.model;import lombok.AllArgsConstructor;import lombok.Getter;import lombok.Setter;@Setter@Getter@AllArgsConstructorpublic class Message {    public enum MessageType {        HI,        GOODBYE,        CHAT    }    private MessageType messageType;    private String target;}  

很简单,不用多说,我们要模拟的场景是针对不同的messageType及target(也就是不同的业务规则 ),代码能做出不同的处理。

 

三、编写业务规则drl文件

drl 是drools rule的缩写,大概长这个样子:(规则文件一般放在resources资源目录或下面的子目录中),将下面的内容保存在hello.drl中

package com.cnblogs.yjmyzz.drools;import com.cnblogs.yjmyzz.drools.demo.model.Message;import java.util.concurrent.atomic.AtomicInteger;global String temp;global AtomicInteger count;//函数示例function void print(String messgae){    System.out.println(messgae);}//规则1rule "say-hi"    when        $message: Message(Message.MessageType.HI.equals(messageType) && target!=null)    then        print("hi," + $message.getTarget() + ", welcome to drools\n");    end

这里面可以分成几个部分:

3.1 package部分

这个是用来管理包的,跟java的package概念类似,多个rule文件时,可以按包来管理rule代码。

3.2 import

drl 规则文件中,可以直接使用java定义好的类,只需要import进来就好。

3.3 global

相当于全局变量声明,多个规则文件中可共享该变量(后面会演示这一用法),要注意的是:共享全局变量建议不要用Integer这种"简单"类型,这样无法在规则文件中修改变量的"值",建议用复杂类型(比如上面的AtomicInteger)

3.4 function

即:函数,可以定义一些共用函数,在本drl文件被其它规则共用。

3.5 rule ... when ... then ... end

这个就是真正的规则了,rule后面的"say-hi"为规则名称,when后面的相当于判断条件(注:声明条件的同时,还能声明所谓fact"变量"-[不太准确,暂且这样叫吧],$message: Message(...) 这里就相当于把后面一串东西,保存在$message这个fact"变量中)

小结一下:上面这个规则,相当于,如果Message的实例,其messageType为HI,且target值不为空,就打印输出一句话。

很简单吧,我们再加点难度,多加几个规则 :

package com.cnblogs.yjmyzz.drools;import com.cnblogs.yjmyzz.drools.demo.model.Message;import java.util.concurrent.atomic.AtomicInteger;global String temp;global AtomicInteger count;//函数示例function void print(String messgae){    System.out.println(messgae);}//规则1rule "say-hi"    when        $message: Message(Message.MessageType.HI.equals(messageType) && target!=null)    then        print("hi," + $message.getTarget() + ", welcome to drools\n");    endrule "say-goodbye"    when        $message: Message(Message.MessageType.GOODBYE.equals(messageType) && target!=null)    then        print("bye bye ," + $message.getTarget() + "\n");    endrule "chat-and-goodbye"    when        $message: Message(Message.MessageType.CHAT.equals(messageType) && target!=null)    then        print($message.getTarget() +  ", nice to meet you. But I have to go.");        //将MessageType设置成GOODBYE        $message.setMessageType(Message.MessageType.GOODBYE);        //更新fact,以便触发规则"say-goodbye"        update($message);    endrule "give-me-money"    salience -1 //规则触发的优先级,值越大,越先触发    when        $message: Message(target.equals("beggar"))    then        print("5毛拿好");    endrule "give-me-rice"    salience 1    when        $message: Message(target.equals("beggar"))    then        print("给你个包子吧");    end//本规则的效果:如果target="loop",会循环触发,真到10次后停下rule "loop"//    no-loop  //加上这行后,将禁止循环触发    when        $message: Message(target.equals("loop") && count.get()<10)    then        print("\n我会每隔1秒触发,10次后停止!" + count.addAndGet(1));        Thread.sleep(1000);        update($message)    end

解释下:

a: "chat-and-goodbye" 这条规则,如果messageType=CHAT,会修改$message.messageType为GOODBYE,然后update($mesage),相当于修改了Message实例后,会重新匹配say-goodbye规则

b:"give-me-money"、"give-me-rice" 这二个规则设置了salience,其实就是优先级,值越大,该规则越优先匹配。

c: "loop" 最后一条规则,这里用到了一个全局变量count,每次该规则且匹配到以后,计数器+1,然后再update,又匹配到本条规则,最终规则就是循环触发10次。

 

一个项目里,可以同时有多个规则文件,还可以再加一个hello2.drl,演示共享变量

package com.cnblogs.yjmyzz.drools;import com.cnblogs.yjmyzz.drools.demo.model.Message;rule "global-demo"    salience -99    when        $message: Message(target.equals("beggar"))    then        System.out.println(temp);    end

这里打印了共享变量temp(前提是target="begger")

 

四、resource/META-INF里放置kmodule.xml文件

内容如下:

这个文件的主要作用之一,是在运行时,让drools知道加载哪些drl文件。注意:这里packages="hello",就表示加载classpath:resources/hello下的drl文件。

最后项目的文件结构类似这样:

 

五、跑一把

HelloApp内容如下:

package com.cnblogs.yjmyzz.drools.demo;import com.cnblogs.yjmyzz.drools.demo.model.Message;import org.kie.api.KieServices;import org.kie.api.runtime.KieContainer;import org.kie.api.runtime.KieSession;import java.util.concurrent.atomic.AtomicInteger;public class HelloApp {    public static void main(String[] args) {        KieContainer kContainer = null;        try {            KieServices ks = KieServices.Factory.get();            kContainer = ks.getKieClasspathContainer();            KieSession kSession = kContainer.newKieSession("ksession-hello");            Message message1 = new Message(Message.MessageType.HI, "杨过");            kSession.insert(message1);            kSession.fireAllRules();            Message message2 = new Message(Message.MessageType.GOODBYE, "姑姑");            kSession.insert(message2);            kSession.fireAllRules();            Message message3 = new Message(Message.MessageType.CHAT, "美羊羊");            kSession.insert(message3);            kSession.fireAllRules();            Message message4 = new Message(null, "beggar");            kSession.setGlobal("temp", "我是谁?我在哪?我要干什么?");            kSession.insert(message4);            kSession.fireAllRules();            Message message5 = new Message(null, "loop");            kSession.setGlobal("count", new AtomicInteger(0));            kSession.insert(message5);            kSession.fireAllRules();        } catch (Exception e) {            e.printStackTrace();        } finally {            if (kContainer != null) {                kContainer.dispose();            }        }    }}

注意下共享变量,即:message4,message5部分,一般是在规则触发前提前把共享变量先设置好初始值,最终输出如下:

hi,杨过, welcome to drools //规则:say-hibye bye ,姑姑 //规则:say-goodbye美羊羊, nice to meet you. But I have to go. //规则:chat-and-goodbyebye bye ,美羊羊 //规则: say-goodbye(2次匹配成功)给你个包子吧 //规则:give-me-rice5毛拿好 //规则:give-me-money我是谁?我在哪?我要干什么?//hello2.drl中的规则"global-demo"我会每隔1秒触发,10次后停止!1 //规则:loop循环10次我会每隔1秒触发,10次后停止!2我会每隔1秒触发,10次后停止!3我会每隔1秒触发,10次后停止!4我会每隔1秒触发,10次后停止!5我会每隔1秒触发,10次后停止!6我会每隔1秒触发,10次后停止!7我会每隔1秒触发,10次后停止!8我会每隔1秒触发,10次后停止!9我会每隔1秒触发,10次后停止!10

  

参考文章:

 

 

附:文件drools-helloworld可从github下载

转载于:https://www.cnblogs.com/yjmyzz/p/drools-tutorial.html

你可能感兴趣的文章
华为交换机端口镜像
查看>>
简易爬虫(爬取本地数据)
查看>>
一位菜鸟的java 最基础笔记
查看>>
python 进程间通信
查看>>
字符串和编码
查看>>
servlet(一)
查看>>
异常实验
查看>>
python \r与\b的应用、光标的含义
查看>>
深拷贝 vs 浅拷贝 释放多次
查看>>
Java环境变量PATH和CLASSPATH
查看>>
ERROR:bokeh.core.validation.check:E-1001 (BAD_COLUMN_NAME) 就是补存在这个列名
查看>>
assert 的作用是什么?
查看>>
收藏夹(持续更新)
查看>>
iOS中的#import和class区别
查看>>
节约内存,请使用标签页管理工具:onetab、better onetab
查看>>
jQuery中的事件与动画
查看>>
页面加载骨架
查看>>
关于android系统不关屏设置
查看>>
SONY VPCS138EC降级安装XP
查看>>
[luogu4201][bzoj1063]设计路线【树形DP】
查看>>