一个简单的Drools规则引擎用例,可动态更新配置规则

一个简单的Drools规则引擎用例,可动态更新配置规则

前言

规则引擎是由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。

本文描述的是一个简单的SpringBoot + Drools项目用例。用例中使用的是Drools规则引擎的无状态会话(StatelessKIESession)。为方便排版部分代码已经过删减,完整代码可到“项目地址”获取。

项目提供两个API接口:

  1. 执行规则引擎
  2. 动态更新规则

引入依赖

   <!-- Drools -->
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>7.4.1.Final</version>
    </dependency>

执行规则引擎

项目中默认提供两个drl规则文件,对应生成两个会话(单个会话可对应多个drl文件),会话为无状态会话,不使用推理,形成最简单的用例。

<kbase name="firstRules" packages="rules.first">
    <ksession name="firstSession" type="stateless"/>
</kbase>

<kbase name="secondRules" packages="rules.second">
    <ksession name="secondSession" type="stateless"/>
</kbase>

规则一: 传入Student对象,通过age匹配规则设置对象的message。drl文件中两个rule仅优先级不同,此文件测试global参数的使用与优先级测试。

rule "myTest two"
	dialect "java"
	no-loop true
	lock-on-active true
    activation-group "myTest"
    salience 30
	when
        std:Student(age > 10)
	then
        std.setMessage(str + ":priority-30");
end

规则二: 传入Student对象,通过age判断是否成年,并在name后添加备注。

rule "match two"
	dialect "java"
	no-loop true
	lock-on-active true
    activation-group "match"
    salience 20
	when
        std:Student(age >= 18);
	then
        std.setName(std.getName() + "-已成年");
end

执行规则引擎:传入参数age=18, name=‘小明’。

    @ApiOperation(value = "执行规则引擎")
    public BaseResponse<String> executeDrools() {
        BaseResponse<String> result = new BaseResponse<>();
        executeService.configData(paramlist, KieSessionType.SECOND);
		...
        return result;
    }

返回结果:

{
“message”: “Student{age=18, name=‘小明-已成年’, message=‘匹配成功:priority-30’}”
}

动态更新规则

    @ApiOperation("动态更新规则")
    public BaseResponse<String> updateKieSession(@RequestParam(value = "type") @ApiParam("规则文件类型") String type,
                                                 @RequestBody MultipartFile[] requestList) throws Exception {

        BaseResponse<String> result = new BaseResponse<>();
        ...
        stringList.add(kieUpdateService.readDrlByStream(stream));
        ... 
        result = kieUpdateService.updateByFile(type, stringList);
        ...
        return result;
    }

复制规则一的drl文件到本地,在文件中增加加一条rule:

rule "myTest three"
	dialect "java"
	no-loop true
	lock-on-active true
    activation-group "myTest"
    salience 40
	when
        std:Student(age > 10)
	then
        std.setMessage(str + ":priority-40");
end

传入本地的drl文件,动态更新session后再次执行规则引擎,返回结果如下:

{
“message”: “Student{age=18, name=‘小明-已成年’, message=‘匹配成功:priority-40’}”
}

动态更新规则过程

  1. 将输入的drl文件转变为字符串
    public String readDrlByStream(InputStream inputStream) {
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                bos.write(buffer, 0, length);
            }
            return bos.toString();
        } catch (IOException e) {
            LOGGER.error("Read file error");
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                LOGGER.error("Close stream error");
            }
        }
        return null;
    }
  1. 使用转为字符串的drl文件,更新指定名称的KieSession
    public boolean updateKieSession(String session, List<String> drlStrList) {
        //1.生成新的KieSession
        KieHelper helper = new KieHelper();
        //添加传入规则
        for (String str : drlStrList) {
            helper.addContent(str, ResourceType.DRL);
        }
        Results results = helper.verify();
        if (results.hasMessages(Message.Level.WARNING, Message.Level.ERROR)) {
            List<Message> messages = results.getMessages(Message.Level.WARNING, Message.Level.ERROR);
            for (Message message : messages) {
                LOGGER.error("规则语法异常: {}", message.getText());
            }
            throw new IllegalStateException("规则文件语法错误!");
        }
        //生成StatelessKieSession对象,方法一
        //KieBaseConfiguration configuration = helper.ks.newKieBaseConfiguration();
        //configuration.setOption(EventProcessingOption.STREAM);
        //StatelessKieSession kieSession = helper.build(configuration).newStatelessKieSession();
        //方法二
        StatelessKieSession kieSession = helper.build(MultithreadEvaluationOption.YES).newStatelessKieSession();

        //2.校验Kiesession
        KieSessionType kieSessionType = KieSessionType.getVaule(session);
        if (kieSessionType.equals(KieSessionType.OTHER)) {
            LOGGER.error("Session名称错误: " + session);
            return false;
        }

        //3.更新Kiesession
        kieContainerService.updateKieSession(kieSession, kieSessionType);

        return true;
    }

项目地址

https://gitee.com/enchanted-ys/drools-demo
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值