Drools 之 KieModule 版本管理
来源:互联网 发布:儿童桌面软件 编辑:程序博客网 时间:2024/05/16 17:10
Drools 作为一个优秀的开源规则引擎,它的功能无疑是非常强大的。与普通的规则硬编码相比,Drools 有着非常多的优点,比如:规则的动态更新、规则配置的可视化等。
1. 规则动态更新的简单描述
使用或了解过 Drools 的小伙伴们应该知道它里面定义了很多的概念,其中有一个比较重要的就是 KieModule,而 Drools 的规则动态更新也就是基于对 KieModule 地动态加载。由于一般在现实的使用场景中,规则内容都会被打包成一个 Jar 文件,然后由 KieScanner 根据 Jar 的 GAV(groupId/artifactId/version) 对其进行扫描加载,从而实现规则的动态更新。那么 Drools 是怎样根据 GAV 来控制规则的版本管理的呢?
2. KieModule 仓库
在 Drools 里面,规则包是强依赖于 Maven 的,规则管理的抽象模型也与其基本一致,与 Maven 的 jar 仓库类似,Drools 也有着自己的仓库对 KieModule 进行管理,当然,Drools 的仓库只是程序代码中一个概念。
Drools 的仓库非常简单,首先,我们来看一下仓库相关的类图:
类的层次结构非常简单,一个接口,一个实现类,就完成了整个对 KieModule 的管理,当然只限于 KieModule,不包含其里面的 KieBase、KieSession 之类的。
而对于 KieModule 的管理,所有的操作也只有三种:添加(addKieModule)、删除(removeKieModule)、获取(getKieModule)。而这三类操作却全部委派给 KieRepositoryImpl.KieModuleRepo 这个内部类来完成了,这个类将是我们学习的重点。
2.1. KieModuleRepo 的属性设置
KieModuleRepo 属性:用于定义 KieModule 缓存区的大小。
// GA 缓存的最大 Size 相关属性public static final String CACHE_GA_MAX_PROPERTY = "kie.repository.project.cache.size";static final int MAX_SIZE_GA_CACHE // made changeable for test purposes = Integer.parseInt(System.getProperty(CACHE_GA_MAX_PROPERTY, "100"));// Version 缓存的最大 Size 相关属性public static final String CACHE_VERSIONS_MAX_PROPERTY = "kie.repository.project.versions.cache.size";static final int MAX_SIZE_GA_VERSIONS_CACHE // made changeable for test purposes = Integer.parseInt(System.getProperty(CACHE_VERSIONS_MAX_PROPERTY, "10"));
2.2. KieModule 缓存
KieModule 的缓存分为两类:
- KieModule 缓存: 缓存分为两级,第一级:键为 GA(规则包的 groupId 及 artifactId),值为 NavigableMap,也称为 GA 缓存 。其中 NavigableMap 是同 GA 不同 Version 的一组 KieModule。
- OldKieModule 缓存: 主要存储旧版本的 KieModule。键为 GAV,这里用一个实体类 ReleaseId 来表示。
// KieModules 缓存区,大小为 GA Sizefinal Map<String, NavigableMap<ComparableVersion, KieModule>> kieModules = new LinkedHashMap<String, NavigableMap<ComparableVersion, KieModule>>(16, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry<String, NavigableMap<ComparableVersion, KieModule>> eldest) { return (size() > MAX_SIZE_GA_CACHE); }};// oldKieModules 缓存区,大小为 GA Size * Version Sizefinal LinkedHashMap<ReleaseId, KieModule> oldKieModules = new LinkedHashMap<ReleaseId, KieModule>() { @Override protected boolean removeEldestEntry(Map.Entry<ReleaseId, KieModule> eldest) { return size() > (MAX_SIZE_GA_CACHE * MAX_SIZE_GA_VERSIONS_CACHE); }};
上述的两个缓存区都使用 LinkedHashMap 实现了 LRU(近期最少使用)算法,用来控制缓存区的大小,在缓存区无多余容量时,将最少使用的 KieModule 移出缓存区(新技能 Get)。
2.3. 添加 KieModule
整个 KieModule 的添加流程可以分成三步:
第一步:ReleaseId 的拆解,即分为 GA 与 Version。
第二步:KieModule 二级缓存 NavigableMap 的获取(创建)。
第三步:备份旧的 KieModule,并添加新的 KieModule。
synchronized void store(KieModule kieModule) { ReleaseId releaseId = kieModule.getReleaseId(); // 拼接 groupId 及 artifactId 用来标识仓库里面一组同 GA 的 KieModule String ga = releaseId.getGroupId() + ":" + releaseId.getArtifactId(); // 根据 KieModule 的版本号通过某种算法计算出一个可比较的版本 ComparableVersion comparableVersion = new ComparableVersion(releaseId.getVersion()); // 获取相同 GA 的 KieModule 集合 NavigableMap<ComparableVersion, KieModule> artifactMap = kieModules.get(ga); if( artifactMap == null ) { artifactMap = createNewArtifactMap(); kieModules.put(ga, artifactMap); } // 正式添加 KieModule 之前,备份旧的 KieModule KieModule oldReleaseIdKieModule = oldKieModules.get(releaseId); // variable used in order to test race condition if (oldReleaseIdKieModule == null) { KieModule oldKieModule = artifactMap.get(comparableVersion); if (oldKieModule != null) { oldKieModules.put( releaseId, oldKieModule ); } } // 正式添加 KieModule artifactMap.put( comparableVersion, kieModule );}
在这三步操作中,第一步里面有一个 ComparableVersion 的计算,这里暂时不做赘述,详情请参考 ComparableVersion 的实现。重点看一下第二步中的 NavigableMap 的初始化,也是版本管理中的重中之重。
private NavigableMap<ComparableVersion, KieModule> createNewArtifactMap() { // 使用实现 TreeMap 匿名内部类,作用:保证 KieModule 缓存中元素按照 ComparableVersion 进行排序 NavigableMap<ComparableVersion, KieModule> newArtifactMap = new TreeMap<ComparableVersion, KieModule>() { // 此处定义一个 Map 指向 TreeMap 本身的实例,是因为需要在索引队列中,对真实的 KieModule 缓存进行了删除操作 // 而匿名内部类无法访问到外部类的实例,所以增加一个 final 的引用指向外部类的一个实例,即真实的缓存容器 private final Map<ComparableVersion, KieModule> artifactMap = this; // 使用 LinkedHashMap 实现一个 LRU 队列,存储了真实缓存 artifactMap 里面的 Key(相当于索引),下面称索引队列 // 主要作用:限制 KieModule 缓存容器的无限增长 LinkedHashMap<ComparableVersion, Object> backingLRUMap = new LinkedHashMap<KieRepositoryImpl.ComparableVersion, Object>(16, 0.75f, true) { @Override protected boolean removeEldestEntry( Map.Entry<ComparableVersion, Object> eldest ) { // 当集合中元素数量超过缓存允许的最大限制时,移除最老(根据访问顺序或插入顺序判断)的元素 boolean remove = (size() > MAX_SIZE_GA_VERSIONS_CACHE); // 根据 backingLRUMap 存储的索引删除真实缓存 artifactMap 里面的 KieModule if( remove ) { artifactMap.remove(eldest.getKey()); } return remove; } }; @Override public KieModule put( ComparableVersion key, KieModule value ) { // 向索引队列里面插入一个最新的索引 backingLRUMap.put(key, PRESENT); // 向真实缓存 artifactMap 中插入最新的 KieModule,此处不可以使用 artifactMap 直接调用,会造成死循环 return super.put(key, value); } }; return newArtifactMap;}
可以看到注释比代码还要多,由此可见这段代码的逻辑较之前面的代码复杂了很多。此段代码我们从变量入手来剖析它:
- newArtifactMap:这是此方法的最终结果,用来存储同 GA 的 KieModule 的集合,每个 KieModule 需要按照版本号进行排序,所以将其类型定义为 TreeMap。由于同一个集合不能同时为 TreeMap 与 LinkedHashMap,所以它借用了 backingLRUMap 来帮它完成 LRU 的功能。
- backingLRUMap:存储 KieModule 在 newArtifactMap 中的索引,即 ComparableVersion,对其进行 LRU 排序,协助 newArtifactMap 完成限制缓存大小的功能。
- artifactMap:backingLRUMap 为一个内部类实现,但它需要获取对其外部类实例的一个操作权限,所以它必须持有外部类实例的引用,因此,artifactMap 的诞生完美地解决掉了这个问题。
程序虽然短小,但设计十分精巧,令人叹服。
- Drools 之 KieModule 版本管理
- 版本管理之SVN
- 版本管理之SVN
- drools之helloworld
- Rule Engine之Drools
- git版本管理工具之版本管理
- 版本管理系统之GIT
- 版本管理之初接触
- 版本管理:Git之常用命令
- 【Maven实战】之版本管理
- 软件研发管理之版本管理
- Drools规则引擎之WorkingMemory
- 规则引擎 学习之--Drools
- Drools
- drools
- drools
- drools
- Drools
- 分析实时嵌入式系统软件调试问题
- HDU 2647:Reward
- numpy模块笔记之linspace
- Tomcat安装后出现the JRE_HOME environment variable is not defined correctly
- 循环依赖 导致 registered the JDBC driver [oracle.jdbc.OracleDriver] but failed to unregist
- Drools 之 KieModule 版本管理
- PPTV面试题——括号消除
- set的简单应用
- 嵌入式软件调试方法
- python下载数据集存放位置
- oj刷题—Problem J: 螺旋方阵
- python笔记之可变参数* and **
- 网易面试题——双核处理
- UVALive