Drools 6.0 Hello World

2 篇文章 0 订阅
1 篇文章 0 订阅

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值