Drools 6.0 Hello World

来源:互联网 发布:sql rownum 编辑:程序博客网 时间:2024/06/07 04:41

0x00 开始

Drools是JBoss旗下的一款开源规则引擎。

规则引擎可以实现业务规则和代码的分离,使得非技术人员也可以配置业务规则,使业务规则有更强的可维护性。而Drools是开源的规则引擎中使用最广泛的。

目前Drools的最高版本是7.0.0beta,网上大多数例子都是以Drools 5.x为例,而中文的Drools 6.x 例子较少,在本文中已Drools 6.4.0.Final为例,只使用Drools 6.x的新API。
官方文档地址:
https://docs.jboss.org/drools/release/6.4.0.Final/drools-docs/html_single/

Drools 6.0对5.x的主要改进有:
1. Kie API整合了jBPMUberFire等等一票项目,Kie的意思是Knowledge is everything
2. 利用maven repo管理规则,分离系统和规则代码,根据maven版本更新规则。
3. PHREAK算法,官方文档认为其改善了多线程下的性能
4. 支持定时器表达式

0x01 例子

由于Drools 6.0 和maven高度耦合,所以建议项目都使用maven管理。

规则项目

pom.xml

    <groupId>org.drools.test</groupId>    <artifactId>artifact-rule</artifactId>    <version>1.0</version>

Drools的规则预发并没有什么变化,这里只演示最简单的规则
放在src/main/resources/pkg/rule.drl

import drools.Bean;rule "Len0"when    m : Bean( value == 0 )then    System.out.println("Hello World 0");end# ......rule "Len999"when    m : Bean( value == 999 )then    System.out.println("Hello World 999");end

定义KieModulesrc/main/resources/META-INF/kmodule.xml,注意rule、pkg、first,这必须和其他配置匹配。

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

主项目

maven依赖:

<!-- 不需要再关心每个Drools组件的版本了 --><dependencyManagement>    <dependencies>        <dependency>            <groupId>org.drools</groupId>            <artifactId>drools-bom</artifactId>            <type>pom</type>            <version>6.4.0.Final</version>            <scope>import</scope>        </dependency>    </dependencies></dependencyManagement><dependencies>    <dependency>        <groupId>org.kie</groupId>        <artifactId>kie-api</artifactId>    </dependency>    <dependency>        <groupId>org.drools</groupId>        <artifactId>drools-compiler</artifactId>        <scope>runtime</scope>    </dependency>    <!-- 引入规则项目 -->        <dependency>        <groupId>org.drools.test</groupId>        <artifactId>artifact-rule</artifactId>        <version>1.0</version>    </dependency></dependencies>     

Bean文件:src/main/java/drools/Bean.java

package drools;public class Bean {    private Integer value; // 唯一的属性    public Integer getValue() {        return value;    }    public void setValue(Integer value) {        this.value = value;    }}

测试文件:

KieServices ks = KieServices.Factory.get();KieContainer kContainer = ks.getKieClasspathContainer();// 从默认的kmodule.xml路径读取KieModule配置,然后根据kmodule.xml中的定义查找drl文件KieSession kSession = kContainer.newKieSession("first");for (int i = 0; i < 100; ++i) {    Bean bean = new Bean();    bean.setValue(i);    kSession.insert(bean);    kSession.fireAllRules();}

0x02 无状态Session

Drools 6.x 文档中将PHREAK算法描述为一个惰性规则匹配算法,当有多个线程并发请求Drools执行规则时,只会有一个线程会执行,而其他线程在kSession.fireAllRules();会直接返回,而不做任何执行(该方法返回执行的Fact数目,所以此时返回0)。

所以如果需要一个同步的规则匹配并执行,则需要使用无状态的Session。
修改src/main/resources/META-INF/kmodule.xmltype="stateless"

<?xml version="1.0" encoding="UTF-8"?><kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">    <kbase name="rule" packages="pkg">        <ksession type="stateless" name="first" />    </kbase></kmodule>
KieServices ks = KieServices.Factory.get();KieContainer kContainer = ks.getKieClasspathContainer();StatelessKieSession kSession = kContainer.newStatelessKieSession("first");for (int i = 0; i < 100; ++i) {    Bean bean = new Bean();    bean.setValue(i);    kSession.execute(bean);}

查看源代码可知,其底层是对有状态的Session进行了包装,只是会做一次复制,这样当前线程就是这个Session唯一的执行线程了,可以保证同步调用。

0x03 动态规则加载

规则引擎最大的好处是规则和系统分离,这使得可以单独更新规则。6.x与maven耦合,可以直接通过maven坐标更新规则。

KieServices ks = KieServices.Factory.get();KieContainer kContainer = ks.newKieContainer(        ks.newReleaseId("org.drools.test", "artifact-rule", "1.0") );StatelessKieSession kSession = kContainer.newStatelessKieSession();

在更多的时候,我们希望自己进行规则的生成和加载,最直接的想法是给定一个规则字符串,直接更新。
(此时不需要kmodule.xmlrule.drl

KieServices ks = KieServices.Factory.get();KieFileSystem kfs = ks.newKieFileSystem();kfs.write("src/main/resources/simple.drl", ruleString); // ruleString是规则字符串KieBuilder kb = ks.newKieBuilder(kfs);kb.buildAll();// 以下几行代码可以看到载入错误Results results = kb.getResults();if (results.hasMessages(org.kie.api.builder.Message.Level.ERROR)) {    System.out.println(results.getMessages());    throw new IllegalStateException("### errors ###");}KieContainer kContainer = ks.newKieContainer(kb.getKieModule().getReleaseId());StatelessKieSession kSession = kContainer.newStatelessKieSession();

Drools底层仍然是动态生成一个如同maven打包的jar,然后再将其载入。

Drools会将规则动态地编译成类以构建整个引擎,所以动态加载规则时候不可能避免地会占用一部分持久代,那么会OOM吗?
在我的机器上,我用以下JVM参数,启用了类卸载

-Xmx1024m-XX:PermSize=64m-XX:MaxPermSize=64m-XX:+CMSClassUnloadingEnabled

规则是前面提到的rule.drl文件,一千条简单等于规则,结果:

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"

说明是会OOM的。但是如果将持久代区域提高到128M,在我的机器上则不会发生OOM。
但动态加载后几乎每次都触发了FullGC,此时GC+加载时间会从几十秒到几百秒(是的,单位是秒)。将持久代大小提高后,可以减少触发FullGC的频率,但每次触发FullGC之后的加载还是耗时很久。(这里测试的规则较简单占用内存相对较少,真实的规则文件会导致不同的加载时间和内存占用)

0x04 定时器

Drools 6.x的一个新功能是直接支持在表达式中编写定时器,Drools规则支持的定时方法有很多,这里只演示基于cron表达式的规则。

规则文件rule.drl,每秒打印一次时间

import java.util.Date;rule "Timer"    timer (cron:0/1 * * * * ?)when    eval(true)then    System.out.println(new Date());end

调用代码

KieServices ks = KieServices.Factory.get();// 启用定时器规则KieSessionConfiguration ksconf = ks.newKieSessionConfiguration();ksconf.setOption( TimedRuleExectionOption.YES );KieContainer kContainer = ks.getKieClasspathContainer();KieSession kSession = kContainer.newKieSession("first", ksconf);kSession.fireAllRules();

0x05 总结

Drools 6.x 并没有什么有价值的改进,6.x仍可以使用5.x的API。
另外这样一个规则稍微一多就吃内存的规则引擎,到底有多大意义?

0 0
原创粉丝点击