1.Drools规则引擎简介
2.Drools规则引擎基本语法
Drools 规则引擎中,标准的规则文件就是以“ drl ”结尾的文本文件,由于它是标准的文本文件,因此可以通过一些记事本工具对其进行査阅和编辑,也可以存储在数据库中。规则内容是放在规则文件中的,一个规则文件可以存放多个规则体。除此之外,规则文件还可以存放用户自定义的函数、数据对象及自定义査询等。
一套完整的规则文件内容如表2-1所示。
关键字 | 描述 |
---|---|
package | 包名,只限于逻辑上的管理,若自定义的查询或函数位于同一包名,不管物理位 |
import | 规则引用问题,导入类或方法 |
global | 全局变量 |
function | 自定义函数 |
queries | 查询 |
rule end | 规则体,后续基本用到规则体中的特性 |
由于篇幅限制,仅介绍与系统应用到的重要关键字进行介绍。
package:除 package 之外,其他关键字在规则文件中的顺序是任意的,规则文件中必须要有一 个 package 声明,并且 package 声明要放在规则文件的第一行(规则模板”除外)。规则文件中的 package 和 Java 语言中的 package 有相似之处,不同的是在 Java 文件中 package 是用来把功能相似或相关的文件放在同一个 package 下进行管理。这种 package 管理既有物理上 Java 文件位置的管理,又有逻辑上文件位置的管理;在 Java 文件中通过 package 管理文件要求文件位置在逻辑上与物理上都要保持一致。在 Drools 规则引擎的规则文件中, package 对于规则文件中规则的管理只限于逻辑上的管理,并不管规则文件所在的物理目录,这是规则文件与 Java 类文件中 package 的区别。
同一个 package 下,用户可以自定义函数、自定义查询等,不管这些函数与查询是否在同一个规则文件中,都是可以直接使用的,这与 Java 中同一 package 的 Java 类调用相似。
rule end :规则内容中的规则体,是进行业务规则判断、处理业务结果的部分。规则体语法结构如表2-2所示。
关键字 | 描述 |
---|---|
rule | 规则开始,参数是规则的唯一名称 |
attributes | 规则属性,是rule和when之间的参数,为可选项 |
when | 规则条件部分,决定then部分是否执行 |
then | 规则结果部分 |
end | 规则结束 |
在订单流程系统中,关键配置信息为when部分,该部分由具体业务人员配置具体业务规则确定。
单个drl规则示例:
rule "test-pattern-rule"
when
then
System.out.println("规则被触发");
end
具体的业务执行中,then语句会替换成具体的Java执行接口,如视图接口以及业务方法等。
3.多个规则执行控制
上述章节已经展示了单个规则是如何执行的,但是订单的流程驱动中涉及到多个任务节点,并且节点与节点之间涉及到串行、并行、互斥等执行关系,势必会需要在规则与规则之间做出逻辑控制。
串行:多个规则执行文件默认由上至下执行,天然具有串行执行特点。
互斥:使用drools关键字 "activation-group",该属性特点是:激活分组,通过字符串定义分组名称,具有相同组名称的规则体只有一个规则被激活,其他的规则即使为true,也不会进行执行,达成互斥目的。
String activicationName = "activation-group " + "\"" + "mutualGroup" + "\"";
并行:由于drools规则引擎没有自带并行执行特性,这部分内容通过自研java开发实现,配置为并发标记的节点携带的规则,单独由一个规则文件进行承载。以下为并行组件的部分源码:
for (Object object : jsonArray) {
JSONObject jsonObject = (JSONObject) object;
String key = jsonObject.getString("id");
String parallelRuleBody = ruleService.findById(jsonObject.getString("code")).getDroolsRule();
String ruleName = "rule " + "\"" + key + "\"" + " ";
parallelRuleString = parallelRuleString + ruleName + parallelRuleBody + " ";
if (jsonObject.containsKey("children")) {
childrenTreeMap.put(key, jsonObject.getJSONArray("children"));
}
}
KieBase kieBase = DroolsUtil.getKieBase(parallelRuleString);
List <Future<Exception>> list = new LinkedList <>();
for (Object object : jsonArray) {
try {
Future <Exception> future = cs.submit(new Callable <Exception>() {
@Override
public WaitException call() throws WaitException {
try {
JSONObject jsonObject = (JSONObject) object;
String key = jsonObject.getString("id");
reloadService.runChildrenTree(kieBase, childrenTreeMap, flowInstId, key, dataId, flowCode);
return null;
} catch (WaitException e) {
return new WaitException();
}
}
});
list.add(future);
} catch (WaitException e) {
}
}
以上举例订单中心实现的最基本的流程控制规则,限于篇幅,一些实现的复杂特性不再赘述。
4、整合Springboot以及整体实现流程
首先在pom文件中添加drools依赖:
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools.version}</version>
</dependency>
以及单个规则执行的样例代码:
KieBase kieBase = DroolsUtil.getKieBase(ruleString);
long dataIdL = Long.parseLong(dataId);
JSONObject orderData = orderProviderConsumerService.getOrderDataById(dataIdL);
KieSession session = kieBase.newKieSession();
try {
session.addEventListener(new RuleFireListener());
session.setGlobal("orderData", orderData);
// 设置全局变量
session.setGlobal("nodeChildrenMap", jsonMap);
// 传入流程实例Id
session.setGlobal("flowInstId", flowId);
session.setGlobal("orderId", dataId);
session.setGlobal("flowCode", flowCode);
session.fireAllRules();
}finally {
session.dispose();
}
在每个控制节点从数据库获得配置规则数据组装成规则文件后,通过上述代码执行相应规则。
其中orderData是传入规则中的全局变量,因为规则执行的元数据来自于订单数据。具体的路径也由此传入。
图4-1 流程启动流程图