drools规则引擎及springboot快速接入最佳实践

1、简介

drools是从Jboss  开源的规则引擎框架,使用规则文件用于替代复杂多变的if-else条件判断,使规则和核心业务拆开,规则单独配置避免业务变化需要修改代码重新上线问题,其决策表也利于非开发人员通过Excel进行一些规格修改关停,规则文件或扩展的决策表需要遵循一定的语法格式,语法格式比较简单,且idea的drools插件提供了该文件类型的代码提示。

2、适用场景

如果业务if-else不是复杂多变的,使用规则引擎会增加较大的维护成本,应优先考虑后台进行规则管理。比如用户积分业务

https://blog.csdn.net/luhaichuan88/article/details/84659712

3、流程描述

读取规则文件或决策表生成KieSession,设置KieSession的全局变量等属性并传入要评估的对象开始评估,评估结果可塞入Kie全局变量,最后关闭KieSession

4、快速整合

4.1依赖(https://github.com/hongwen1993/fast-drools-spring-boot-starter ),该依赖间接引入drools的几个包,并自动配置了KieTemplate对象方便了文件读取

 
            com.github.hongwen1993
            fast-drools-spring-boot-starter
            2.0.6
 

4.2 drl规则文件,语法介绍参考https://blog.csdn.net/quzishen/article/details/6163012

package com.rules
dialect "java"

import  com.example2020.demo.entity.Address;
import java.util.HashMap;


global java.util.Map map;//全局变量


rule "描述:邮编为6个数字"
activation-group "test"
salience 6666
    when
        $address : Address(postcode != null && postcode matches "([0-9]{6})");  //评估对象:对象类型(评估表达式)
    then   //then后可以写Java代码,可直接使用Kie上下文对象kcontext
        System.out.println(map.get("inparam")); //获取Java传入的参数
        map.put("outparam","out>>>>>>>>>>>>>>>");
        $address.setPostcode("1234");
        update($address);
        System.out.println("邮编正则6数字!"+$address);
        //throw new RuntimeException("xxxxxxx");
        //kcontext.getKieRuntime().getAgenda().getAgendaGroup("agenda").setFocus();
end

rule "描述:邮编为4个数字"
    when
        $address : Address(postcode != null && postcode matches "([0-9]{4})")  //评估对象:对象类型(评估表达式)
    then
        System.out.println("邮编正则4数字!"+$address);
end




rule "描述:判断集合"
activation-group "test" //同一组只触发一个高优先级的
salience 999  //优先级
    when
       // $address : Address(shopIds.size()==2 && shopIds contains "123")  //评估对象:对象类型(评估表达式)
       $address:Address();
       $shopId:Long(this==123 || this==345) from $address.shopIds; //循环
    then
        System.out.println("判断集合!"+$address);
end




rule "描述:session显式激活该agenda-group才能触发"
timer (cron: 0/2 * * * * ?)
agenda-group "agenda" //优先级很高
    when
        $address : Address(postcode != null && postcode matches "([0-9]{6})")  //评估对象:对象类型(评估表达式)
    then
        System.out.println("显式激活!"+$address);
end




rule "drools定时任务"
timer (cron: 0/2 * * * * ?)
//timer(int:5s)
    when
       eval(true)
    then
        System.out.println("每两秒!");
end



rule "drools entry-point测试"
    when
       $address : Address(postcode != null && postcode matches "([0-9]{6})") from entry-point "point";
    then
        System.out.println("drools entry-point测试!");
end

4.3 Java代码

package com.example2020.demo;

import com.drools.core.KieTemplate;
import com.example2020.demo.entity.Address;
import org.drools.core.event.DefaultAgendaEventListener;
import org.drools.core.reteoo.builder.EntryPointBuilder;
import org.kie.api.KieServices;
import org.kie.api.event.rule.*;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.HashMap;

@SpringBootApplication
@RestController
public class DemoApplication {
    @Autowired
    private KieTemplate kieTemplate;
    
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    @GetMapping("/test/{postCode}")
    public void test(@PathVariable(value = "postCode") String postCode) throws Exception {
        //1读取文件创建KieSession对象
        //KieSession session = kieTemplate.getKieBase("rule1.drl").newKieSession();
        //String context = kieTemplate.encodeToString("D:\\drools\\rule1.drl");//,可以是excel决策表,读的绝对路径,文件内容考虑存Redis
        //KieSession session = kieTemplate.decodeToSession(context);
        //String context = kieTemplate.encodeToString(this.getClass().getClassLoader().getResource("rule1.drl").getPath());//可以是excel决策表,相对路径获取绝对路径,文件内容考虑存Redis
        //KieSession session = kieTemplate.decodeToSession(context);
        KieSession session = kieTemplate.getKieSession("rule1.drl");
        //2.如果规则文件“then 后Java代码较复杂”可考虑使用事件监听以解耦
        useEventListener(session);
        //3.要评估的对象
        Address address = new Address();
        address.setPostcode(postCode);
        address.setShopIds(Arrays.asList(123L, 345L));
        //4.设置session属性,如开启agenda,设置全局变量等
        session.getAgenda().getAgendaGroup("agenda").setFocus(); //功能类似entry-point
        session.getEntryPoint("point").insert(address);//drools规则有from entry-point "point"的规则会被执行,功能类似agenda
        HashMap map = new HashMap<>();
        map.put("inparam", "in>>>>>>>>>>>>>>>>");
        session.setGlobal("map", map);
        //5.往session插入要评估的对象并启动评估,评估结果处理
        session.insert(address);//可以insert多个
        //session.fireUntilHalt();会同时启动drl里的定时任务一直循环,不能执行后面代码
        int ruleFiredCount = session.fireAllRules();
        String outparam = map.get("outparam").toString();//获取规则文件往全局变量塞入的参数
        //6.关闭session及评估结果处理   
        session.dispose();//session是有状态的,需要关闭,还有另一个StatelessKnowledgeSessionImpl。只是不用显式dispose,execute里finally 自动关闭了session
        System.out.println("触发了" + ruleFiredCount + "条规则,全局变量" + outparam);
    }


    private void useEventListener(KieSession session) {
        session.addEventListener(new RuleRuntimeEventListener() {
            @Override
            public void objectInserted(ObjectInsertedEvent objectInsertedEvent) {
                System.out.println(objectInsertedEvent.getObject());
            }
            @Override
            public void objectUpdated(ObjectUpdatedEvent objectUpdatedEvent) {
            }
            @Override
            public void objectDeleted(ObjectDeletedEvent objectDeletedEvent) {
            }
        });
        session.addEventListener(new DefaultAgendaEventListener() {   //覆盖默认实现,如果直接实现接口太多需要方法实现
            @Override
            public void matchCreated(MatchCreatedEvent event) {
                event.getKieRuntime();
                System.out.println("agenda matchCreated");
            }
            @Override
            public void beforeMatchFired(BeforeMatchFiredEvent event) {
                System.out.println("agenda beforeMatchFired");
            }
            @Override
            public void afterMatchFired(AfterMatchFiredEvent event) {
                System.out.println("agenda afterMatchFired");
            }
        });
    }
}

4.4、决策表,drl规则文件的衍生版,老少皆宜的规则文件,适合规则量大但格式一致(条件判断condition及结果处理action),需要非开发人员进行修改规则。参考:https://blog.csdn.net/wo541075754/article/details/78848178

官网:https://www.drools.org/

 

你可能感兴趣的:(other)