Drools规则引擎实践直白总结

Drools规则引擎,网上大把相关的文章介绍,但我感觉不够直白,理解有些困难,且知识点没有集中比较分散、有些还是早前版本的内容,对与新手来说上手可能比较慢,而且比较容易走弯路,故我在深入研究并实践于项目中后,在空闲时间花费精力整理了这篇文章,分享出来,便大家快速上手。


            org.kie
            kie-spring
            7.55.0.Final

 public Object checkRule(Object msg) {
        List drlContentList=new ArrayList<>();

        //当一个Fact对象为集合对象时的判断
        //这个是当把某个集合(List)当成一个fact传入工作内存中后,规则有效
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "import java.util.List;\n" +
                "rule \"test rule 0\"\n" +
                "when \n" +
                "$list:List(size>0) \n" +
                "$msg:Message(createBy==\"zuowj\") from $list \n " +
                "then\n" +
                "System.out.println(\"hello zuowj! ---rule 0\");\n" +
                "$msg.setReplyBy(\"rule 0\");\n" +
                "end");

        //普通Pattern 模式+字段约束
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 1\"\n" +
                "when \n" +
                "$msg:Message(createBy==\"zuowj\")\n " +
                "then\n" +
                "System.out.println(\"hello zuowj! ---rule 1\");\n" +
                "$msg.setReplyBy(\"rule 1\");\n" +
                "end");

        //accumulate 内联方式(类似for循环处理)
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 2\"\n" +
                "when \n" +
                "exists(Message(createBy==\"zuowj\"))\n"+
                "$res:String() from accumulate(Message(createBy==\"zuowj\",$cont:content),init(String allContent=\"\";),action(allContent +=$cont;),result(allContent))"+
                "then\n" +
                "System.out.println($res +\"---rule 2\");\n" +
                "end");

        //accumulate 普通函数方式
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 2-2\"\n" +
                "when \n" + "accumulate(Message(createBy==\"zuowj\",$id:id);$countNum:count($id);$countNum>1) \n"+
                "then\n" +
                "System.out.println(\"count number:\"+ $countNum +\"---rule 2-2\");\n" +
                "end");

        //not,不满足时
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
               "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 3\"\n" +
                "when not Message()\n" +
                "then\n" +
                "System.out.println(\"no message don't say hello! ---rule 3\");\n" +
                "end");

        //exists,匹配执行一次
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 4\"\n" +
                "when exists(Message(createBy==\"zuowj\"))\n" +
                "then\n" +
                "System.out.println(\"exists Message(createBy==zuowj) fact! ---rule 4\");\n" +
                "end");

        //forall,工作内存中所有fact对象必需都满足时才匹配规则
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 5\"\n" +
                "when forall(Message(createBy==\"zuowj\"))\n" +
                "then\n" +
                "System.out.println(\"for all Message(createBy==zuowj) fact! ---rule 5\");\n" +
                "end");

        //collect,将工作内存中所有fact对象添加到同一个集合中
        drlContentList.add("package zuowenjun.drools.rule.demo\n" +
                "import cn.zuowenjun.model.Message;\n" +
                "rule \"test rule 6\"\n" +
                "when Message() && $msgs:List(size>=9) from collect(Message(createBy==\"zuowj\"))\n" +
                "then\n" +
                "System.out.println(\"collect all Message fact(size=\" + $msgs.size() +\")! ---rule 6\");\n" +
                "end");

        KieHelper kieHelper=new KieHelper();
        for(String drl:drlContentList){
            kieHelper.addContent(drl,ResourceType.DRL);
        }

        KieBase kieBase = kieHelper.build();
        StatelessKieSession kieSession = kieBase.newStatelessKieSession();
        if (msg instanceof List){
            kieSession.execute((List)msg);
        } else{
            kieSession.execute(msg);
        }

        return msg;
    }

//单元测试
/**
 * @author zuowenjun
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DroolsDemoApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class RuleTests {

    @Autowired
    private RuleDemo ruleDemo;

    @Test
    public void testRule() {
        List msgList=new ArrayList<>();
        for(int i=1;i

思路:1.定义规则内容(即:规则执行单元),2.定义贯穿整个规则执行链条的上下文,内部就放fact、global等,具体实现参照如下示例代码【注意:如果仅是示例测试代码,并不规范,仅为演示提供思路】,整个规则执行采取:责任链的设计模式,即:每个规则只负责满足自己条件的执行逻辑,最后更新上下文中相关的内容。

//规则链上下文,里面就包含fact集合,全局对象及执行过的rule
    public class RuleChainContext {
        public List factList;
        public static Map global;
        public RuleUnit execedRule;
    }

 //规则执行单元抽象类(这里用抽象类而没有用接口,是因为我要限定组织逻辑,可以理解为模板用法)
    public abstract class RuleUnit {
        public RuleUnit nextExecedRule;

        protected String name;

        public abstract String getName();

        public abstract boolean matchWhen(RuleChainContext context);

        public abstract void doThen(RuleChainContext context);

        public final void execute(RuleChainContext context) {
            if (matchWhen(context)) {
                doThen(context);
            }
            if (context.execedRule == null) {
                context.execedRule = this;
            }
            context.execedRule.nextExecedRule = this;
        }

    }

通过单元测试模拟调用:

 @Test
    public void testDefRules() {
        List ruleUnitList = new ArrayList<>();
        ruleUnitList.add(new RuleUnit() {
            @Override
            public String getName() {
                name= "rule-1";
                return name;
            }

            @Override
            public boolean matchWhen(RuleChainContext context) {
                return context.factList.stream().anyMatch(f->f instanceof Integer && 1==(Integer)f);
            }

            @Override
            public void doThen(RuleChainContext context) {
                System.out.println("rule[include 1] do");
                //TODO:context
            }
        });

        ruleUnitList.add(new RuleUnit() {
            @Override
            public String getName() {
                name= "rule-2";
                return name;
            }

            @Override
            public boolean matchWhen(RuleChainContext context) {
                return context.factList.stream().anyMatch(f->f instanceof Integer && 2==(Integer)f);
            }

            @Override
            public void doThen(RuleChainContext context) {
                System.out.println("rule[include 2] do");
                //TODO:context
            }
        });

        RuleChainContext context=new RuleChainContext();
        context.factList=new ArrayList<>();
        context.factList.add(1);//加入1则触发规则1
        context.factList.add(2);//加入2则触发规则2,若减少规则相应减少

        for(RuleUnit ruleUnit:ruleUnitList){
            ruleUnit.execute(context);
        }

        System.out.println("result context:\n" + JsonUtils.deserializer(context));

    }

最终结果:

rule[include 1] do
rule[include 2] do
result context:
{"factList":[1,2],"execedRule":{"nextExecedRule":{"nextExecedRule":null,"name":"rule-2"},"name":"rule-1"}}

从输出的结果可以看出,还是可以达到规则引擎的简单效果的,当然如果想在生产环境实际应用自己实现的”类规则引擎”代码,实现规则与执行分开,也可将规则执行单元(RuleUnit)实现类单独放到一个JAR包,然后再借助于URLClassLoader实现动态加载并添加自定义的实现规则执行单元(RuleUnit)的类,最后执行即可。【.NET方面的同学实现亦同理】

注:文中相关名词解释来源于网上,并非原创,我这里仅为知识点总结!

可参考相关drools系列文章:

Original: https://www.cnblogs.com/zuowj/p/14949715.html
Author: 梦在旅途
Title: Drools规则引擎实践直白总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/592248/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Spring1

    一、简介: Spring : 为简化开发而生,但是后期由于各类组件的增多,使得其配置过于繁琐,本身就是一个大杂烩 , 整合现有的框架技术,渐渐的被称为了”配置地狱&#8…

    Java 2023年6月9日
    098
  • 了解下 Kuberentes Gateway API

    在 Kubernetes 集群边缘对外提供网络服务的时候,通常需要借助 Ingress 对象,这个对象提供了暴露 Service 所必须的核心要素,例如基于主机名的路由、对 URL…

    Java 2023年6月5日
    085
  • 中国近代发展史顺序(二)

    建党初期: 1.中止一大:1921年7月 (上海、浙江嘉兴)宣告了中国共xx的成立,选举陈独秀为中央局书记。 2.中共二大:1922年7月 (上海)制定了党的最高纲领和最低纲领。 …

    Java 2023年6月5日
    078
  • main 方法可以继承吗?

    阿里二面:main 方法可以继承吗? 昨天,微信群里一位网友,在群里发了自己面试阿里的过程。其中一个面试,他在群里 PUA 其他网友。这道面试题就是: Java &#x4E…

    Java 2023年6月7日
    097
  • 【Java面试手册-算法篇】给定一个字符串,输出逆序字符串

    在Java中,如果想要逆序输出字符串,通常可以采样首尾双向循环、单向循环或者StringBuffer、StringBuilder来实现,下面分别给出相应的示例代码。 示例代码1 —…

    Java 2023年6月8日
    085
  • nginx防盗链接的使用

    以 local.hyperf.com为例 nginx配置文件如下 至少需要一个 Hyperf 节点,多个配置多行 upstream hyperf { # Hyperf HTTP S…

    Java 2023年5月30日
    064
  • Spring事件监听机制源码解析

    Spring事件监听器使用 1.Spring事件监听体系包括三个组件:事件、事件监听器,事件广播器。 事件:定义事件类型和事件源,需要继承ApplicationEvent。 pac…

    Java 2023年6月13日
    080
  • java限制方法执行时间;Future使用

    public static void main(String[] args) { ThreadPoolTaskExecutor threadPoolTaskExecutor = n…

    Java 2023年5月29日
    093
  • SpringBoot的自动配置实现和介绍

    自动配置实现逻辑 –> 约定大于配置 在spring4.0时提出了 Condition相关注解, Condition相关注解可以让用户提供一个判断条件,从而返回t…

    Java 2023年5月30日
    073
  • 刚入职没多久,连夜手写了一个代码生成器,项目开发速度瞬间屌炸了!

    一、简介 最近刚入职一个新团队,还没来得及熟悉业务,甲方爸爸就要求项目要在2个月内完成开发并上线! 本想着往后推迟1个月在交付,但是甲方爸爸不同意,只能赶鸭子上架了! 然后根据业务…

    Java 2023年6月9日
    095
  • 也许互联网大厂BAT更看重你的计算机基础知识(2022必看的操作系统,计算机网络的学习方式

    校招面试求职,大厂学导航认准「 小龙coding」,致力于打造全网最佳大厂进阶台~ 大家好,我是小龙。 我们都知道无论是在工作还是学*中,对于每个程序员,计算机基础一定是特别重要的…

    Java 2023年6月5日
    079
  • nginx配置常用 ( 反向代理时传客户端IP )

    反向代理时传客户端IP csharp;gutter:true;location / { proxy_set_header X-Forwarded-For $remote_addr;…

    Java 2023年5月30日
    060
  • JAVA的Proxy动态代理在自动化测试中的应用

    JAVA的动态代理,在MYBATIS中应用的很广,其核心就是写一个interface,但不写实现类,然后用动态代理来实例化并执行这个interface中的方法,话不多说,来看一个实…

    Java 2023年5月29日
    074
  • MongoDB快速入门

    1.介绍 Mongodb:是一个nosql的数据库的一种数据库,他是介于关系型数据库与非关系型数据库之间的一种数据库,也可以理解为它是介于Redis与Mysql之间的一种数据库。它…

    Java 2023年6月9日
    0103
  • Spring 依赖注入循环依赖问题解决

    项目中可能会出现两个service需要相互调用的情况,两个service相互调用会造成bean循环依赖,Spring在应用程序上下文启动时就会去创建所有的单例bean对象,从而导致…

    Java 2023年6月7日
    086
  • rocketmq批量消息投递

    批量发送消息可提高传递小消息的性能。同时也需要满足以下特征 批量消息要求必要具有同一 topic、相同消息配置 &#x4E0D;&#x652F;&#x630…

    Java 2023年6月16日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球