Drools的KieSession(有状态会话)的获取,领导就说一句话,员工加班都做不完!

news2025/2/24 3:51:00

使用Drools规则引擎的代码,最简单的主要有以下几部分:

//这一部分的连接:“万恶”之源的KieServices,获取代码就一行,表面代码越少里面东西就越多,本以为就是个简单的工厂方法,没想到里面弯弯绕绕这么多东西_zcrazy胡说八道的博客-CSDN博客

KieServices ks = KieServices.Factory.get();

//这一部分的理解:规则的加载与管理者——KieContainer的获取与其类型的区别(虽然标题是KieContainer,其实说的还是KieServices)_zcrazy胡说八道的博客-CSDN博客

KieContainer kContainer = ks.getKieClasspathContainer();

//今天讲解这一部分

KieSession kSession = kContainer.newKieSession();

目录

获取KieSessionModel

获取KieBase

根据KieBaseModel名字获取KieBase

获取KieBaseModel

创建KieBase

获取KieSession

总结


会话分为有状态会话和无状态会话,本篇主要是有状态会话的获取的源码过程,就按照上面的代码段来讲,没有传入任何的参数,全部使用默认的值来获取会话。源代码如下:

代码段1 KieContainerImpl类中的newKieSession方法

public KieSession newKieSession() {
    return this.newKieSession(
        (Environment)((Environment)null), 
        (KieSessionConfiguration)null);
}

public KieSession newKieSession(Environment environment, KieSessionConfiguration conf) {
    return this.newKieSession((String)null, environment, conf);
}

//按照上面两个方法,传进去的参数全部是null
public KieSession newKieSession(String kSessionName, 
                        Environment environment, 
                        KieSessionConfiguration conf) {
                      
    //因为传进来的参数全是null,所以会走findKieSessionModel(false)这一条线
    //获取KieSessionModel,用来创建KieSession的模型
    KieSessionModelImpl kSessionModel = kSessionName != null ? 
        (KieSessionModelImpl)this.getKieSessionModel(kSessionName) : 
        (KieSessionModelImpl)this.findKieSessionModel(false);
        
    if (kSessionModel == null) {
        log.error("Unknown KieSession name: " + kSessionName);
        return null;
    } else {
        //方法名已经很直接了,从kieSessionModel中获取kieBase
        //将上一步获取的kieSessionModel作为参数传入进去
        KieBase kBase = this.getKieBaseFromKieSessionModel(kSessionModel);
        if (kBase == null) {
            return null;
        } else {
            //conf是null,所以会调用 this.getKieSessionConfiguration((KieSessionModel)kSessionModel), environment);
            KieSession kSession = kBase.newKieSession(conf != null ? conf : 
                    this.getKieSessionConfiguration((KieSessionModel)kSessionModel), 
                    environment);
                    
            this.registerNewKieSession(
                    kSessionModel, 
                    (InternalKnowledgeBase)kBase, kSession);
                    
            return kSession;
        }
    }
}

从上面的方法来看,想要获取到有状态的会话,先要获取一个KieSessionModel,然后通过KieSessionModel获取KieBase,再从KieBase中获取KieSession,再将获取到的KieSession放入到缓存中,方便频繁的获取KieSession。

获取KieSessionModel

代码段2 KieContainerImpl类中的findKieSessionModel方法

//因为是有状态会话,所以stateless传入的是false
//会调用this.kProject.getDefaultKieSession()
private KieSessionModel findKieSessionModel(boolean stateless) {
    KieSessionModel defaultKieSessionModel = stateless ? 
            this.kProject.getDefaultStatelessKieSession() : 
            this.kProject.getDefaultKieSession();
    if (defaultKieSessionModel == null) {
        throw new RuntimeException(stateless ? "Cannot find a default StatelessKieSession" : "Cannot find a default KieSession");
    } else {
        return defaultKieSessionModel;
    }
}

这一段没什么好解释的,就是根据通过传入的参数来返回默认的会话,因为当前是有状态会话,所以会去getDefaultKieSession方法,这个方法就如其名字一样,至于内部的代码,之后讨论KieProject的时候再去研究。

获取KieBase

代码段3 KieContainerImpl类中的getKieBaseFromKieSessionModel方法

private KieBase getKieBaseFromKieSessionModel(KieSessionModel kSessionModel) {
    if (kSessionModel.getType() == KieSessionType.STATELESS) {
        //从findKieSessionModel获取的默认kieSessionModel,是有状态的,所以不会进入到这里来
        throw new RuntimeException("Trying to create a stateful KieSession from a stateless KieSessionModel: " + kSessionModel.getName());
    } else {
        //通过kieSessionModel获取kieBaseModel
        KieBase kBase = this.getKieBase(kSessionModel.getKieBaseModel().getName());
        if (kBase == null) {
            log.error("Unknown KieBase name: " + kSessionModel.getKieBaseModel().getName());
            return null;
        } else {
            return kBase;
        }
    }
}

将上一步获取到的KieSessionModel作为参数,传入到这个方法中去,这个方法里面会通过KieSessionModel来获取建立KieBase的KieBaseModel,然后通过KieBaseModel的名字来获取对应的KieBase

根据KieBaseModel名字获取KieBase

代码段4 KieContainerImpl类中的getKieBase方法

public KieBase getKieBase(String kBaseName) {
    //从缓存中获取kieBase
    KieBase kBase = (KieBase)this.kBases.get(kBaseName);
    if (kBase == null) {
        //如果缓存中没有kieBase,就先获取kieBasemodel
        KieBaseModelImpl kBaseModel = this.getKieBaseModelImpl(kBaseName);
        synchronized(kBaseModel) {
            kBase = (KieBase)this.kBases.get(kBaseName);
            if (kBase == null) {
                BuildContext buildContext = new BuildContext();
                //创建一个kieBase
                kBase = this.createKieBase(kBaseModel, 
                                this.kProject, 
                                buildContext, 
                                (KieBaseConfiguration)null);
                if (kBase == null) {
                    throw new RuntimeException("Error while creating KieBase" + buildContext.getMessages().filterMessages(new Level[]{Level.ERROR}));
                }
                //将创建的kieBase放入缓存中,下一次就可以直接获取到了
                this.kBases.put(kBaseName, kBase);
            }
        }
    }
    return kBase;
}

从这段代码里面看出,进入该方法后,会先通过KieBase的名字从缓存中查找对应的KieBase,但是如果是第一次调用,肯定是查找不到对应的KieBase,所以就会先获取KieBaseModel用来建立KieBase,建立KieBase是一个同步操作,也就是说同一时间只能有一个线程执行该操作,在创建之前,也要先从缓存中先获取一次,防止有其他线程先执行了新建操作。如果此时KieBase还是空,就说明没有其他线程新建过,缓存中也不存在该KieBase,可以着手新建了。

获取KieBaseModel

代码段5 KieContainerImpl类中的getKieBaseModelImpl

private KieBaseModelImpl getKieBaseModelImpl(String kBaseName) {
    //从当前的kieProject中获取kieBaseModel
    KieBaseModelImpl kBaseModel = (KieBaseModelImpl)
                this.kProject.getKieBaseModel(kBaseName);
    if (kBaseModel == null) {
        throw new RuntimeException("The requested KieBase \"" + kBaseName + "\" does not exist");
    } else {
        return kBaseModel;
    }
}

简单的来说就是直接从KieProject中获取KieBaseModel,这个KieProject会在之后详细分析。

创建KieBase

代码段6 KieContainerImpl类中的createKieBase

private KieBase createKieBase(KieBaseModelImpl kBaseModel, 
                    KieProject kieProject, 
                    BuildContext buildContext, 
                    KieBaseConfiguration conf) {
    if (log.isInfoEnabled()) {
        log.info("Start creation of KieBase: " + kBaseModel.getName());
    }

    //获取创建KieBase的KieModel
    InternalKieModule kModule = kieProject.getKieModuleForKBase(kBaseModel.getName());
    //通过KieModel的方法创建KieBase,具体怎么创建的等到了KieModel在说
    InternalKnowledgeBase kBase = kModule.createKieBase(kBaseModel, kieProject, buildContext, conf);
    //这个方法是在KieBase建立之后调用,可以用于执行一些与模型相关的操作
    //例如更新模型的配置、添加或删除规则等
    kModule.afterKieBaseCreationUpdate(kBaseModel.getName(), kBase);
    if (kBase == null) {
        return null;
    } else {
        kBase.setResolvedReleaseId(this.containerReleaseId);
        kBase.setContainerId(this.containerId);
        kBase.setKieContainer(this);
        kBase.initMBeans();
        if (log.isInfoEnabled()) {
            log.info("End creation of KieBase: " + kBaseModel.getName());
        }
        return kBase;
    }
}

获取KieSession

之前的步骤需要的代码大部分都是在Container中就可以看到,这一步的创建KieSession是在KieBase的代码中才能看到,需要先获取到KieSession的配置

代码段7 KieContainerImpl类中的getKieSessionConfiguration

private KieSessionConfiguration getKieSessionConfiguration(KieSessionModel kSessionModel) {
    KieSessionConfiguration ksConf = 
            (KieSessionConfiguration)this.sessionConfsCache
                                .computeIfAbsent(kSessionModel.getName(), 
                                                (k) -> {
                                                    return 
                                                    new SessionConfigurationImpl(
                                                        (Properties)null, 
                                                        this.kProject.getClassLoader()
                                                    );
                                 });
    ksConf.setOption(kSessionModel.getClockType());
    ksConf.setOption(kSessionModel.getBeliefSystem());
    return ksConf;
}

代码段8 KnowledgeBaseImpl类中的newKieSession方法

//environment传入为null
public KieSession newKieSession(KieSessionConfiguration conf, Environment environment) {
    return this.newKieSession(conf, environment, false);
}

KieSession newKieSession(KieSessionConfiguration conf, Environment environment, boolean fromPool) {
    //通过代码段7来看,这地方不会为null
    if (conf == null) {
        conf = this.getSessionConfiguration();
    }

    SessionConfiguration sessionConfig = (SessionConfiguration)conf;
    //传入的参数为null,所以会从这里获取Environment
    if (environment == null) {
        environment = EnvironmentFactory.newEnvironment();
    }

    if (this.getConfiguration().isSequential()) {
        throw new RuntimeException("Cannot have a stateful rule session, with sequential configuration set to true");
    } else {
        //整了一个重入读写锁
        this.readLock();

        StatefulKnowledgeSessionImpl var5;
        try {
            //获取KieSession
            var5 = this.internalCreateStatefulKnowledgeSession(environment, sessionConfig, fromPool);
        } finally {
            //解锁重入读写锁
            this.readUnlock();
        }

        return var5;
    }
}

这样KieSession就获取成功了,获取的详细代码,在之后的内容中可能会涉及,请持续关注,感谢!~

总结

获取KieSession是一个非常复杂的过程,根据用户手册来说,KieSession是从KieBase中获取的,KieBase是从KieContainer中获取的,而且都会有默认的,也可以在kmodul.xml文件中配置。文章中出现了很多KiePaoject等相关控件,会在之后的内容中陆续解析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/927022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows下编译NextCloud desktop 3.9.1

首先从官方下载源码: https://github.com/nextcloud/desktop💻 Desktop sync client for Nextcloud. Contribute to nextcloud/desktop development by creating an account on GitHub.https://github.com/nextcloud/desktop 我选择的是3.9.1的稳定版本…

工控机引领移动机器人的智能化革命!

随着制造业数字化转型的加速,工业4.0时代的到来,工业互联网逐步成为中国推进新型工业化进程的核心驱动力量。而工控机作为工业互联网领域的重要组成部分,已经在越来越多行业得到广泛应用。据中商情报网数据显示,2022年我国工业自动…

Linux CentOS7系统,抓取http协议的数据包

使用 tcpdump 命令 1.首先确认是否安装 [rootlocalhost ~]# which tcpdump /usr/bin/which: no tcpdump in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin) [rootlocalhost ~]#我这里没有安装 1.1 安装 tcpdump yum install tcpdump 安装成功如下&#xf…

【Linux】进程间通信原理与Reactor模式

一、用户进程缓冲区和内核缓冲区 缓冲区的目的,是为了减少频繁的系统IO调用。大家都知道,系统调用需要保存之前的进程数据和状态等信息,而结束调用之后回来还需要恢复之前的信息,为了减少这种损耗时间、也损耗性能的系统调用&…

有趣的无限缓存OOM现象

作者:邹阿涛涛涛涛涛涛 想必大家都知道OOM是啥吧,我就不扯花里胡哨的了,直接进入正题。先说一个背景故事,我司app扫码框架用的zxing,在很长一段时间以前,做过一系列的扫码优化,稍微列一下跟今天…

学习ts(九)混入

对象混入 使用Object.assign()进行对象混入,最后的people会被识别为三种类型的联合类型 类混入 使用implement并非extnds实现混入。 属性在混入类里面定义,分别在类中占位,方法分别在类中定义,在混合类中占位。这告诉编译器这…

自动化的驱动力,工控机助您实现智能生产!

“智能工厂建设如火如荼,部分成果已经落地,在大规模资金投入的市场催化下,海尔、海信等制造企业通过智能工厂手段推进生产效率成倍增长的新闻层出不穷。在工业4.0时代,“中国制造2025”战略中,智能工厂构建都是其中不可…

激活函数总结(十九):激活函数补充(ISRU、ISRLU)

激活函数总结(十九):激活函数补充 1 引言2 激活函数2.1 Inverse Square Root Unit (ISRU)激活函数2.2 Inverse Square Root Linear Unit (ISRLU)激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函…

用docker-compose搭建LNMP

docker-compose搭建LNMP 一、compose 的部署1.Docker Compose 环境安装 二、编写Docker Compose1.准备依赖文件,配置nginx2.配置mysql3.配置php4.编写docker-compose.yml5.执行6.查看 一、compose 的部署 (1)公司在实际的生产环境中,需要使用…

磁盘阵列/视频集中存储/安防监控视频智能分析平台新功能:人员聚集

人工智能技术已经越来越多地融入到视频监控领域中,近期我们也发布了基于AI智能视频云存储/安防监控视频AI智能分析平台的众多新功能,该平台内置多种AI算法,可对实时视频中的人脸、人体、车辆、物体等进行检测、跟踪与抓拍,支持口罩…

Linux上实现分片压缩及解压分片zip压缩包 - 及zip、unzip命令详解

👨‍🎓博主简介 🏅云计算领域优质创作者   🏅华为云开发者社区专家博主   🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入! 🐋 希望大家多多支…

LiveNVR监控流媒体Onvif/RTSP功能-支持语音对讲支持非国标摄像头SDK语音对讲GB28181级联国标平台非国标转国标语音对讲

LiveNVR支持语音对讲支持非国标摄像头SDK语音对讲GB28181级联国标平台非国标转国标语音对讲 1、确认摄像头是否支持对讲2、摄像头视频类型复合流3、通道配置SDK接入4、视频广场点击播放5、相关问题5.1、如何配置通道获取直播流?5.2、如何GB28181级联国标平台&#x…

AD(第四部分---网表导入及模块化布局设计)

第四部分:网表导入及模块化布局设计 21.导入常见报错解决方法(unknow pin及绿色报错等) 将原理图导入到PCB: 在原理图界面点击右上角设计 导出后,若出现如下错误,则说明没有0805C的电容: 没有电容应该怎么办呢?需要进…

10 倍性价比,万物新生基于 StarRocks 无缝直替 Trino

小编导读: 万物新生成立于2011年,定位为“互联网环保”类型的循环经济企业,是中国最大的二手电子产品交易与服务平台。万物新生集团旗下4大业务线包含:爱回收、拍机堂、拍拍、海外业务 AHS Device。万物新生集团秉承“让闲置不用…

raft算法学习备忘

一致性共识算法 参考:分布式一致性算法应用场景,写了为什么需要共识算法,以及相比于mysql这些主从同步方式的区别。 raft算法简介 一种分布式一致性共识算法的实现方式,机制相比于其它例如paxos来说无论从可读性还是实现机制上要简单很多&…

MQTT协议抓包

MQTT通讯协议的特点 1. 概述 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做…

html-dom核心内容--四要素

1、结构 HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。 2、核心关注的内容:“元素”,“属性”,“修改样式”,“事件反应”。>四要素…

详解numpy.random.shuffle函数

文章目录 函数原型参数解析该函数的注意事项例子示例代码示例结果 参考 numpy的random模块中的shuffle函数用于np.ndarray数组中的元素打乱顺序,进打乱多维数组的第一维顺序。本博客详细节将该函数的API,并给出示例代码和结果。 函数原型 random.shuff…

【计算机网络】HTTPs 传输流程

HTTPS和HTTP的区别 1、HTTP协议传输的数据都是未加密的,是明文的,使用HTTP协议传输隐私信息非常不安 HTTPS协议是由SSLHTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。 2、HTTPS协议需要到CA申请证书,一般…

【C++】开源:Box2D动力学库配置与使用

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍Box2D动力学库配置与使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下&#xff0c…