规则引擎之Drools
一、什么是Drools?
Drools 是一个基于Charles Forgy’s的RETE算法的,易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。
业务分析师人员或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。
Drools 是用Java语言编写的开放源码规则引擎,使用Rete算法对所编写的规则求值。Drools允许使用声明方式表达业务逻辑。可以使用非XML的本地语言编写规则,从而便于学习和理解。并且,还可以将Java代码直接嵌入到规则文件中,这令Drools的学习更加吸引人。
二、规则引擎有什么作用?
比如:一天老板想弄一个活动营销,体验语音识别转账,选择这个时间段多少人进行抽奖,然后就开始写业务逻辑,先查询,然后进行随机筛选,但是,如果领导体验了,必须让领导中奖,本来想法是好的,突然,体验人数不够,或者超了,但是中奖名额就那么多,然后改粒度,本来在100个人抽10个,但是现在改成1000个人抽10个,进行打包上传到服务器上,但是开放人员学聪明了,将数据放到数据库中,但是老板说,下一次要变一下规则,添加红包,或者代金券之类的,这样又要开发部署,然后就有了规则引擎,将业务代码抽取去出来,改成配置文件编写的代码,类似这样,
规则引擎作用,开发者不需要管理业务逻辑,进行开发,产品完成之后,然后将业务规则,变成可以动态处理,随时改变的规则引擎,如果开发者不想自己操作,可以开发一种可视化的拖拽式的操作界面,然后生成规则引擎,或者文档,表格或者.drl
的等可读性代码文件。将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策
三、怎么实现动态规则引擎?
采用Drools+springboot进行开发规则引擎实现。
1.先从数据库获取规则 getActivityRuleList()
2.再跟据获取的规则生成drt可以解析的map型data prepareData(ruleDTO)
3.通过drt解析,生成drl规则string objectDataCompiler.compile(Arrays.asList(data), Thread.currentThread().getContextClassLoader().getResourceAsStream(“give-reward-rule-template.drt”));
4.根据以上获得的规则string生成maven结构的规则并加载 createOrRefreshDrlInMemory(ruleDrls)
四、案例
采用springboot2.1.X与drools7.11.X以上版本pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.citydo</groupId>
<artifactId>springboot_drools</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_drools</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<drools.version>7.11.0.Final</drools.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${drools.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.flink</groupId>
<artifactId>flink-shaded-hive</artifactId>
<version>6.0-flink</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Message.java
package com.citydo.springboot_drools.model;
public class Message {
public static int HELLO = 0;
public static int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
kmodule.xml
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<!--package是文件目录-->
<kbase name="rules" packages="rules,myrules">
<ksession name="ksession-rule"/>
</kbase>
<!--<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">-->
<!--这玩意一定要放在META-INF里面-->
<!--name kbase的唯一标志
packages 路径必须正确可少写可多写可不写
不写的话放于根目录(不建议)
ksession 的唯一标记-->
<!--<kbase name="rules" packages="Drools.rules">-->
<!--<kbase name="rules" packages="rules">-->
<!--<kbase name="rules" packages="">-->
<!--<kbase name="rules" packages="myrules">-->
<!--默认用最后一个-->
<!--<kbase name="rules" packages="rules,myrules">-->
<!-- <ksession name="ksession-rules"/>
</kbase>-->
</kmodule>
Sample.drl
package com.sample.myrules
//package 随便写,但是不可重名
import com.citydo.springboot_drools.model.Message
rule "Hello World"
when
$m : Message( status == Message.HELLO, $myMessage : message )
then
System.out.println( "rules.sample.drl begin1" );
System.out.println( $myMessage);
$m.setMessage( "Goodbye world1" );
$m.setStatus( Message.GOODBYE );
update( $m );
System.out.println( "rules.sample.drl end1" );
end
DroolsTest.java
package com.citydo.springboot_drools;
import com.citydo.springboot_drools.model.Message;
import com.citydo.springboot_drools.utils.DroolsUtil;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
public class DroolsTest {
public static final void main(String[] args) {
try {
// load up the knowledge base
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
//KieSession kSession = kContainer.newKieSession("ksession-rule");
KieSession ksession = DroolsUtil.getKieSessionByName("ksession-rule");
//KieSession kSession = kContainer.newKieSession();
// go !
Message message = new Message();
message.setMessage("Hello World");
message.setStatus(Message.HELLO);
ksession.insert(message);
ksession.fireAllRules();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
DroolsUtils
package com.citydo.springboot_drools.utils;
import org.kie.api.KieServices;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DroolsUtil {
public static final Logger log = LoggerFactory.getLogger(DroolsUtil.class);
/**
* 线程安全单例
*/
private static volatile KieServices kieServices = KieServices.Factory.get();
/**
* KieBase容器,线程安全单例
*/
private static volatile KieContainer kieContainer;
/**
* 加载KieContainer容器
*/
public static KieContainer loadKieContainer() throws RuntimeException {
//通过kmodule.xml 找到规则文件,这个文件默认放在resources/META-INF文件夹
log.info("准备创建 KieContainer");
if (kieContainer == null) {
log.info("首次创建:KieContainer");
// 设置drools的日期格式
System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
//线程安全
synchronized (DroolsUtil.class) {
if (kieContainer == null) {
// 创建Container
kieContainer = kieServices.getKieClasspathContainer();
// 检查规则文件是否有错
Results results = kieContainer.verify();
if (results.hasMessages(Message.Level.ERROR)) {
StringBuffer sb = new StringBuffer();
for (Message mes : results.getMessages()) {
sb.append("解析错误的规则:").append(mes.getPath()).append(" 错误位置:").append(mes.getLine()).append(";");
}
throw new RuntimeException(sb.toString());
}
}
}
}
log.info("KieContainer创建完毕");
return kieContainer;
}
/**
* 根据kiesession 名称创建KieSession ,每次调用都是一个新的KieSession
* @param name kiesession的名称
* @return 一个新的KieSession,每次使用后要销毁
*/
public static KieSession getKieSessionByName(String name) {
if (kieContainer == null) {
kieContainer = loadKieContainer();
}
KieSession kieSession;
try {
kieSession = kieContainer.newKieSession(name);
} catch (Exception e) {
log.error("根据名称:" + name + " 创建kiesession异常");
throw new RuntimeException(e);
}
return kieSession;
}
}
五、规则引擎有哪些?
java开源的规则引擎有:Drools、Easy Rules、Mandarax、IBM ILOG。使用最为广泛并且开源的是Drools。
参考:http://www.cnblogs.com/ydymz/p/9590245.html
参考:https://www.imooc.com/article/25976
参考:https://www.jianshu.com/p/e713860b128e
还没有评论,来说两句吧...