简述
scanner有两个实现 KieRepositoryScannerImpl KieFileSystemScannerImpl
二者区别为 一个是从文件夹检查更新, 一个是从maven仓库检查更新
下面以 KieFileSystemScannerImpl 为例进行演示从文件夹获取更新
然后分析过程 最后自定义一个 KieScanner
准备kjar工程
其实就是个maven项目 存放着规则文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fluffy.mo</groupId>
<artifactId>kjarUpdate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>
|
src\main\resources\META-INF\kmodule.xml
1
2
3
4
5
6
|
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="kb1" packages="vdrl" default="true">
<ksession name="ks-testUpdate" type="stateful" default="true"/>
</kbase>
</kmodule>
|
src\main\resources\vdrl\testUpdate.drl
1
2
3
4
5
6
7
8
9
10
|
package vdrl;
global String tag
rule "aa1"
when
total : Number()
from accumulate( d: Double(), sum( d ) )
then
System.out.println("v1--"+ tag + "--" + total );
end
|
打包成kjar
先打包一次 得到文件 kjarUpdate-0.0.1-SNAPSHOT.jar
修改 pom.xml中的版本号为 0.0.2-SNAPSHOT
修改 testUpdate.drl 中 【v1】为【v2】
再打包 得到文件 kjarUpdate-0.0.2-SNAPSHOT.jar
同上 得到 kjarUpdate-0.0.3-SNAPSHOT.jar
kjar 全部放在 drools-demo-update 文件夹中
1
2
3
4
5
6
|
kjarUpdate-0.0.1-SNAPSHOT.jar
kjarUpdate-0.0.2-SNAPSHOT.jar
kjarUpdate-0.0.3-SNAPSHOT.jar
pom.xml
scanFoler/
src/
|
测试流程
先加载 0.0.1 版本的jar 执行规则,
然后升级到 0.0.2 版本的jar 执行规则,看是否升级成功
调用待测规则
jdk 11
kotlin 1.3.50
drools 7.18.0.Final
DroolsRunMyScanner.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
package fluffy.test_update_rule
import org.kie.api.KieServices
import org.kie.api.builder.ReleaseIdComparator.ComparableVersion
import org.kie.api.runtime.KieSession
import java.util.concurrent.TimeUnit
val pjRoot = "E:\\myprogram\\my_workspace\\code_rep12\\some-task\\drools-demo-update";
// 初版规则 kjar
val kjar = "$pjRoot/kjarUpdate-0.0.1-SNAPSHOT.jar"
// 检查更新的文件夹
val updateFolder = "$pjRoot/scanFoler";
fun main() {
mainV1();
}
fun mainV1() {
val ks = KieServices.Factory.get()
val kModule = ks.repository.addKieModule(ks.resources.newFileSystemResource(kjar))
// 创建container
val kContainer = ks.newKieContainer(kModule.getReleaseId())
// 指定文件夹,每两秒检查一次更新
val scanner = ks.newKieScanner(kContainer, updateFolder)
scanner.start(TimeUnit.SECONDS.toMillis(2))
val kss = kContainer.newKieSession("ks-testUpdate")
kss.setGlobal("tag", "A");
runRule(kss)
println("此处打打断点--在文件夹【scanFoler】放入新的kjar--kjarUpdate-0.0.2-SNAPSHOT.jar-然后继续执行")
TimeUnit.SECONDS.sleep(2)
runRule(kss)
println("完成--可看到之后调用的规则-更新为v2了-对之前创建的session也有效")
}
fun runRule(kss: KieSession) {
kss.insert(1.01)
kss.fireAllRules()
kss.insert(1.02)
kss.fireAllRules()
kss.insert(1.03)
kss.fireAllRules()
}
|
方法 mainV1()
的逻辑为 根据v1版本的jar创建一个容器
新建一个session 运行到断点处,
手动将 kjar–kjarUpdate-0.0.2-SNAPSHOT.jar 放入 scanFoler 文件夹
然后再次触发规则 即可看到 规则已经更新
运行结果
1
2
3
4
5
6
7
8
|
v1--A--1.01
v1--A--2.0300000000000002
v1--A--3.0600000000000005
此处打打断点--在文件夹【scanFoler】放入新的kjar--kjarUpdate-0.0.2-SNAPSHOT.jar-然后继续执行
v2--A--4.07
v2--A--5.09
v2--A--6.12
完成--可看到之后调用的规则-更新为v2了-对之前创建的session也有效
|
分析 KieFileSystemScannerImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.drools.compiler.kie.builder.impl.AbstractKieScanner;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kie.builder.impl.KieContainerImpl;
import org.drools.core.impl.InternalKieContainer;
import org.kie.api.builder.KieScanner;
import org.kie.api.builder.ReleaseIdComparator.ComparableVersion;
import org.kie.api.runtime.KieContainer;
public class KieFileSystemScannerImpl extends AbstractKieScanner<InternalKieModule> implements KieScanner {
private final File repositoryFolder;
private final String kjarFileHead;
private final VersionComparator versionComparator;
public KieFileSystemScannerImpl(final KieContainer kieContainer, final String repositoryFolder) {
this.kieContainer = ( InternalKieContainer ) kieContainer;
// 查询当前的ArtifactId, 以确定文件夹下的新kjar以什么文件名开头
this.kjarFileHead = kieContainer.getReleaseId().getArtifactId() + "-";
// 用来从文件夹下找到最新的kjar
this.versionComparator = new VersionComparator( kjarFileHead.length() );
this.repositoryFolder = new File( repositoryFolder );
}
@Override
protected InternalKieModule internalScan() {
final File newKJar = findNewFile();
return newKJar == null ? null : InternalKieModule.createKieModule(kieContainer.getReleaseId(), newKJar);
}
@Override
protected void internalUpdate(final InternalKieModule kmodule ) {
((KieContainerImpl) kieContainer).updateToKieModule( kmodule );
}
private File findNewFile() { // 如果有新的规则kjar,则返回新kjar
File[] files = repositoryFolder.listFiles((dir, name) -> name.startsWith(kjarFileHead) && name.endsWith(".jar" ));
if (files == null || files.length == 0) {
return null;
}
File candidateNew = getCandidateNew( files ); // 可能有多个 排序后取最新的
// 比较 文件夹中的kjar版本 和 当前容器中使用的版本 , 返回新版本 或空
int versionComparison = compareVersion(getVersionFromFile(candidateNew, kjarFileHead.length()), kieContainer.getReleaseId().getVersion());
return versionComparison > 0 || ( versionComparison == 0 && kieContainer.getReleaseId().isSnapshot() ) ? candidateNew : null;
}
private File getCandidateNew( File[] files ) {
if (files.length == 1) {
return files[0];
}
final List<File> jarFiles = Arrays.asList(files);
jarFiles.sort(versionComparator.reversed());
return jarFiles.get(0);
}
private static class VersionComparator implements Comparator<File> {
private final int headLength;
private VersionComparator(final int headLength) {
this.headLength = headLength;
}
@Override
public int compare(final File f1, final File f2 ) {
return compareVersion( getVersionFromFile(f1, headLength), getVersionFromFile(f2, headLength) );
}
}
private static int compareVersion(String v1, String v2) {
return new ComparableVersion( v1 ).compareTo( new ComparableVersion( v2 ) );
}
private static String getVersionFromFile(File f, int headLength) {
String name = f.getName();
return name.substring( headLength, name.length()-4 );
}
}
|
测试 drools中比较版本的工具
org.kie.api.builder.ReleaseIdComparator.ComparableVersion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
fun testCompareVersion() {
val v1 = ComparableVersion("myshop-1.0.0-20191101.165906-1.jar")
val v2 = ComparableVersion("myshop-1.0.0-20191104.065907-3.jar")
val v3 = ComparableVersion("myshop-1.2.0-SNAPSHOT.jar")
val v4 = ComparableVersion("myshop-1.10.0-SNAPSHOT.jar")
val v5 = ComparableVersion("myshop-1.10.0.Final.jar")
println(v1.compareTo(v2))
println(v2.compareTo(v3))
println(v3.compareTo(v4))
println(v4.compareTo(v5))
// 结果显示: v5的版本号最大, 没毛病
println(v5.compareTo(v1))
}
|
KieFileSystemScannerImpl 继承了 AbstractKieScanner
调度的逻辑在抽象类中
检查更新的逻辑 在 internalScan 方法中实现
然后 internalUpdate 中将新规则更新到容器中
自定义KieScanner
自定义后 可以从指定检查更新的来源
比如 从数据库查 从某个url去查询
自定义的scanner中 internalScan、 internalUpdate都是复制的 KieFileSystemScannerImpl 的逻辑
通过在 findNewFile 方法中编写自己的检查更新逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package fluffy.test_update_rule;
import org.drools.compiler.kie.builder.impl.AbstractKieScanner;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kie.builder.impl.KieContainerImpl;
import org.drools.core.impl.InternalKieContainer;
import org.kie.api.builder.KieScanner;
import org.kie.api.runtime.KieContainer;
import java.io.File;
public class KieMyScannerImpl extends AbstractKieScanner<InternalKieModule> implements KieScanner {
private final File repositoryFolder;
int count = 1;
public KieMyScannerImpl(final KieContainer kieContainer, final String repositoryFolder) {
this.kieContainer = (InternalKieContainer) kieContainer;
// 查询当前的ArtifactId, 以确定文件夹下的新kjar以什么文件名开头
this.repositoryFolder = new File(repositoryFolder);
}
@Override
protected InternalKieModule internalScan() {
// 同 KieFileSystemScannerImpl 相同
final File newKJar = findNewFile();
return newKJar == null ? null : InternalKieModule.createKieModule(kieContainer.getReleaseId(), newKJar);
}
@Override
protected void internalUpdate(final InternalKieModule kmodule) {
// 同 KieFileSystemScannerImpl 相同
((KieContainerImpl) kieContainer).updateToKieModule(kmodule);
}
private File findNewFile() {
// 查找新文件的逻辑, 此处写死了
count++;
String path = repositoryFolder.getAbsolutePath();
File f = null;
if (count == 2) {
f = new File(path + "/kjarUpdate-0.0.2-SNAPSHOT.jar");
} else if (3 == count) {
f = new File(path + "/kjarUpdate-0.0.3-SNAPSHOT.jar");
}
if (f != null) {
System.out.println("发现新规则--" + f.getName());
}
return f;
}
}
|
运行自定义检测类的逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
fun mainV2() {
val ks = KieServices.Factory.get()
val kModule = ks.repository.addKieModule(ks.resources.newFileSystemResource(kjar))
// 创建container
val kContainer = ks.newKieContainer(kModule.getReleaseId())
val ksss = kContainer.newKieSession("ks-testUpdate")
ksss.setGlobal("tag", "A");
runRule(ksss)
val scanner = KieMyScannerImpl(kContainer, pjRoot)
scanner.start(TimeUnit.SECONDS.toMillis(3))
println("此处不打断点--scanner写死了 两个新版本")
TimeUnit.SECONDS.sleep(4)
runRule(ksss)
TimeUnit.SECONDS.sleep(4)
runRule(ksss)
println("done")
}
|
运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
|
v1--A--1.01
v1--A--2.0300000000000002
v1--A--3.0600000000000005
此处不打断点--scanner写死了 两个新版本
发现新规则--kjarUpdate-0.0.2-SNAPSHOT.jar
v2--A--4.07
v2--A--5.09
v2--A--6.12
发现新规则--kjarUpdate-0.0.3-SNAPSHOT.jar
v3--A--7.130000000000001
v3--A--8.15
v3--A--9.18
done
|
归根结底 还是调用的 kieContainer.updateToKieModule( kmodule );
来更新规则的
文章作者
duansheli
上次更新
2019-12-25
(325c7b3)