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

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

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

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

一、添加依赖项

    <properties><drools.version>6.5.0.Final</drools.version><lombok.version>1.18.2</lombok.version></properties><dependencies><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency></dependencies>

注:不同版本的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
@AllArgsConstructor
public 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);
}//规则1
rule "say-hi"when$message: Message(Message.MessageType.HI.equals(messageType) && target!=null)thenprint("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);
}//规则1
rule "say-hi"when$message: Message(Message.MessageType.HI.equals(messageType) && target!=null)thenprint("hi," + $message.getTarget() + ", welcome to drools\n");endrule "say-goodbye"when$message: Message(Message.MessageType.GOODBYE.equals(messageType) && target!=null)thenprint("bye bye ," + $message.getTarget() + "\n");endrule "chat-and-goodbye"when$message: Message(Message.MessageType.CHAT.equals(messageType) && target!=null)thenprint($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"))thenprint("5毛拿好");endrule "give-me-rice"salience 1when$message: Message(target.equals("beggar"))thenprint("给你个包子吧");end//本规则的效果:如果target="loop",会循环触发,真到10次后停下
rule "loop"
//    no-loop  //加上这行后,将禁止循环触发when$message: Message(target.equals("loop") && count.get()<10)thenprint("\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 -99when$message: Message(target.equals("beggar"))thenSystem.out.println(temp);end

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

 

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

内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"><kbase name="hello" packages="hello"><ksession name="ksession-hello"/></kbase>
</kmodule>

这个文件的主要作用之一,是在运行时,让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-goodbye
bye bye ,美羊羊 //规则: say-goodbye(2次匹配成功)给你个包子吧 //规则:give-me-rice
5毛拿好 //规则: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教程一 
drools 6.5.0官方文档 
Learn Drools: Part I
Learn Drools: Part II (Cross Product)
Learn Drools: Part III (Filter Facts)
Learn Drools (Part 4): Inferences
Learn Drools (Part 5): Truth Maintenance
Learn Drools (Part 6): Rules and Statistics
Learn Drools (Part 7): Salience
Drools语法篇之Global全局变量
《Drools7.0.0.Final规则引擎教程》第4章 global全局变量

附:文件示例代码drools-helloworld可从github下载

Drools(BRMS) 速成教程(上)相关推荐

  1. iOS-raywenderlich翻译-AFNetworking速成教程

    http://blog.csdn.net/beyondvincent/article/details/8691257 本文是由 iOS Tutorial 小组成员 Scott Sherwood撰写,他 ...

  2. AFNetworking速成教程

    AFNetworking速成教程 网络 - 你的程序离开了它就不能生存下去!苹果的Foundation framework中的NSURLConnection又非常难以理解, 不过这里有一个可以使用的替 ...

  3. AFNetworking速成教程(1)

    AFNetworking速成教程(1)   Scott Sherwood  on March 26, 2013 Tweet 这篇文章还可以在这里找到 英语 Learn how to use AFNet ...

  4. html唱吧导航栏,唱吧唱歌技巧速成教程_使用唱吧录歌的小技巧

    唱吧现在越来越多人使用了,很多新手发现在唱歌时录出来的歌效果不是很好,这是有原因的.因为你没有运用唱歌的技巧.在唱吧要唱歌好听,需要运用哪些技巧呢?下面这些是小编为大家推荐的关于唱吧唱歌技巧速成教程. ...

  5. 教程-上传应用公钥并获取支付宝公钥

    教程-上传应用公钥并获取支付宝公钥 1. 点击签名验签工具右下角的"上传公钥"会打开支付宝开放平台网页,输入账号登录.(建议使用IE或Chrome浏览器.)  2. 在" ...

  6. 上树建站教程:新手单页网站制作教程上集

    功能强大. 链接.文件下载等功能,一份源程序可以制造出无数个网站,只需一些超级简单的 页面程序可以随意的编辑.修改,包括:图片.文案.背景.图片滚动  单页型网站:就是一个独立页面的网站,是一个纯HT ...

  7. Hyperledger Fabric 2.0 官方文档中文版 第6章 教程(上)

    Hyperledger Fabric 2.0 官方文档中文版第6章 教程上 总目录 6.教程(上) 将智能合约部署到通道 启动网络 Logspout设置 打包智能合约 安装链码包 批准链码定义 将链码 ...

  8. SpringCloud详细教程(上)

    [订阅专栏合集,关注公众号,作者所有付费文章都能看(持续更新)] 推荐[SpringCloud教程]https://blog.csdn.net/hellozpc/article/details/836 ...

  9. 基于JUPYTER的python主流库新手教程(上)

    基于JUPYTER的python主流库新手教程(上) 作者:二马传奇 0. 基本测试 for i in range(5):print(i,end=",") 0,1,2,3,4, 1 ...

  10. 【中英双语】Visual Studio Code速成教程

    [中英双语]Visual Studio Code速成教程 您需要了解的 Visual Studio Code 的所有信息! 此教程共4.0小时,中英双语字幕,画质清晰无水印,源码附件全 课程英文名:V ...

最新文章

  1. linux -------- 使用xshell ,winscp 连接linux 以及一些问题解决
  2. 反编译工具dnspy的安装与使用;
  3. 广东白云机场俯视图,猜猜像什么
  4. L1,L2,L3三级缓存
  5. 项目支持规划标准文档编写要点
  6. 如何从程序员到架构师?
  7. Electron——常用的工具列表
  8. maven项目没有src/test/java和src/test/resources目录问题解决
  9. 主题:小菜一碟可以怎样说
  10. AIDL的简单使用和注意事项
  11. Linux 下 svn 恢复到指定版本
  12. 失业七个月,面试六十家公司的深圳体验(转贴)
  13. AutoJs学习-录制手指动作
  14. 2021最新微信域名检测后屏蔽举报源码
  15. 1688API详情接口调用展示
  16. 如何申请国家自然科学基金报告学习体会
  17. 色彩原理:三原色、色彩三要素、色彩模型
  18. 完美世界2020业绩快报:游戏业务年营收增35%
  19. actionscript(as) 项目中 使用 fla 加载 fla
  20. 尚硅谷-后台管理系统

热门文章

  1. 工商企业大数据爬虫系统
  2. 科学计算机功能键介绍ndf,DNF:非常实用的五个小技巧,你不会还不知道吧!-dnf快捷键设置...
  3. 泛微自带第三方短信接口
  4. php聊天室简单实现
  5. php gd support = off,PHP GD库中GD函数的用法详解
  6. tenda无线网卡Linux驱动,Ubuntu 10.04上腾达W541U V2.0 无线网卡驱动的使用
  7. 通用模块(4)——EEPROM(AT24C08)
  8. office各版本网盘免费下载
  9. List集合对象去重及按属性去重的8种方法
  10. 运动控制加减速算法(一)