Drools 作为一个优秀的开源规则引擎,它的功能无疑是非常强大的。与普通的规则硬编码相比,Drools 有着非常多的优点,比如:规则的动态更新、规则配置的可视化等。
规则动态更新的简单描述
使用或了解过 Drools 的小伙伴们应该知道它里面定义了很多的概念,其中有一个比较重要的就是 KieModule
,而 Drools 的规则动态更新也就是基于对 KieModule
地动态加载。由于一般在现实的使用场景中,规则内容都会被打包成一个 Jar 文件,然后由 KieScanner
根据 Jar 的 GAV(groupId/artifactId/version) 对其进行扫描加载,从而实现规则的动态更新。那么 Drools 是怎样根据 GAV 来控制规则的版本管理的呢?
KieModule 仓库
在 Drools 里面,规则包是强依赖于 Maven 的,规则管理的抽象模型也与其基本一致,与 Maven 的 jar 仓库类似,Drools 也有着自己的仓库对 KieModule
进行管理,当然,Drools 的仓库只是程序代码中一个概念。
Drools 的仓库非常简单,首先,我们来看一下仓库相关的类图:
类的层次结构非常简单,一个接口,一个实现类,就完成了整个对 KieModule
的管理,当然只限于 KieModule
,不包含其里面的 KieBase
、KieSession
之类的。
而对于 KieModule
的管理,所有的操作也只有三种:添加(addKieModule
)、删除(removeKieModule
)、获取(getKieModule
)。而这三类操作却全部委派给 KieRepositoryImpl.KieModuleRepo
这个内部类来完成了,这个类将是我们学习的重点。
KieModuleRepo 的属性设置
KieModuleRepo
属性:用于定义 KieModule
缓存区的大小。
1 | // GA 缓存的最大 Size 相关属性 |
KieModule 缓存
KieModule
的缓存分为两类:
- KieModule 缓存: 缓存分为两级,第一级:键为 GA(规则包的
groupId
及artifactId
),值为NavigableMap
,也称为 GA 缓存 。其中NavigableMap
是同 GA 不同Version
的一组KieModule
。 - OldKieModule 缓存: 主要存储旧版本的
KieModule
。键为 GAV,这里用一个实体类ReleaseId
来表示。
1 | // KieModules 缓存区,大小为 GA Size |
上述的两个缓存区都使用 LinkedHashMap
实现了 LRU(近期最少使用)算法,用来控制缓存区的大小,在缓存区无多余容量时,将最少使用的 KieModule
移出缓存区(新技能 Get)。
添加 KieModule
整个 KieModule
的添加流程可以分成三步:
第一步:ReleaseId
的拆解,即分为 GA 与 Version
。
第二步:KieModule
二级缓存 NavigableMap
的获取(创建)。
第三步:备份旧的 KieModule
,并添加新的 KieModule
。
1 | synchronized void store(KieModule kieModule) { |
在这三步操作中,第一步里面有一个 ComparableVersion
的计算,这里暂时不做赘述,详情请参考 ComparableVersion
的实现。重点看一下第二步中的 NavigableMap
的初始化,也是版本管理中的重中之重。
1 | private NavigableMap<ComparableVersion, KieModule> createNewArtifactMap() { |
可以看到注释比代码还要多,由此可见这段代码的逻辑较之前面的代码复杂了很多。此段代码我们从变量入手来剖析它:
- newArtifactMap:这是此方法的最终结果,用来存储同 GA 的
KieModule
的集合,每个KieModule
需要按照版本号进行排序,所以将其类型定义为TreeMap
。由于同一个集合不能同时为TreeMap
与LinkedHashMap
,所以它借用了backingLRUMap
来帮它完成 LRU 的功能。 - backingLRUMap:存储
KieModule
在newArtifactMap
中的索引,即ComparableVersion
,对其进行 LRU 排序,协助newArtifactMap
完成限制缓存大小的功能。 - artifactMap:
backingLRUMap
为一个内部类实现,但它需要获取对其外部类实例的一个操作权限,所以它必须持有外部类实例的引用,因此,artifactMap
的诞生完美地解决掉了这个问题。
程序虽然短小,但设计十分精巧,令人叹服。