1.Drools规则引擎简介
Drools 是一款基于 Java 语言的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(这里可以是数据库表),使得业务规则的变更不需要修正项目代码、重启服务器就可以在线上环境立即生效。这里可以理解为动态代码(动态业务)。
规则引擎的核心目的之一是将业务决策从程序代码中分离出来,使其代码与业务解耦合。通过特定的语法内容配置具体的业务规则,由 API 进行解析并对外提供执行接口,再接收输入数据,进行特定的逻辑处理并返回规则执行结果。
2.Drools规则引擎基本语法
Drools 规则引擎中,标准的规则文件就是以“ drl ”结尾的文本文件,由于它是标准的文本文件,因此可以通过一些记事本工具对其进行査阅和编辑,也可以存储在数据库中。规则内容是放在规则文件中的,一个规则文件可以存放多个规则体。除此之外,规则文件还可以存放用户自定义的函数、数据对象及自定义査询等。
一套完整的规则文件内容如表2-1所示。
表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所示。
表2-2 规则体语法结构
关键字描述rule规则开始,参数是规则的唯一名称attributes规则属性,是rule和when之间的参数,为可选项when规则条件部分,决定then部分是否执行then规则结果部分end规则结束
在订单流程系统中,关键配置信息为when部分,该部分由具体业务人员配置具体业务规则确定。
单个drl规则示例:
rule "test-pattern-rule"
System.out.println("规则被触发");
具体的业务执行中,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 流程启动流程图
小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看。活动规则是根据用户购买订单的金额给用户送相应的积分,购买的越多送的积分越多,用户可以使用积分来兑换相应的商品,我们这次活动的力度很大,肯定会吸引很多的用户参加,产品经理小王兴高采烈唾液横飞的对小明讲到。小明心想,又tm来这套,这次需求又要变更多少次呢?100元以下,不加分100元-500元加100分500元-1000元加500分。...
Rule Runtime Actions:简单说在执行fireAllRules()之前,都处于这个阶段。
Agenda Evaluation:fireAllRules()之后就转至该阶段,这个阶段主要是匹配Rule,然后触发规则。
###...
package com.drools.rule.req
import com.drools.rule.req.LoginActionReq
rule login_rule_1
$s:LoginActionReq(loginNum==1)
$s.amount=10;
update($s);
代码实现:
public class RuleReq {
//LOGIN、登陆,PAY、支付
订单状态流转是交易系统的最为核心的工作,订单系统往往都会存在状态多、链路长、逻辑复杂的特点,还存在多场景、多类型、多业务维度等业务特性。在保证订单状态流转稳定性的前提下、可扩展性和可维护性是我们需要重点关注和...
一、分解“流程引擎”:
1,设定的“固定流程”,比如流程审批场景里面的“预定审批链”。固定的流程是由运维管理人员设置,链路里包括【节点配置】、【每个节点的找人机制配置】、【每个节点的审批动作设置】、【各个节点互相之间的流转规则】。
“预定审批链”基本包括设置-发起节点(发起人、发起表单结构&内容)、审批节点(审批人)、节点流转规则。
2,驱动业务,是指流程引擎应用在哪些场景的业务。比如电商场景、流程审批场景、C
@[TOC](SpringBoot配合Drools workbench(BusinessCentral)和maven配置实现动态规则)
遇到的困境
如前面的博文《Docker安装drools workbench和kie-server,使用http调用kie-server rest接口传json参数跑规则》所述,折腾了老半天,装好了workbench,终于可以编辑规则了。也配置好了kie server,终于可以动态发布规则了。然而还是遇到点问题:
引入一个kieServer又增加了开发和运维的负担,一个wo
DROOLS_ENUM2_0("drools1_1","rules/drools1_1/"),
DROOLS_ENUM1_1("drools2_0","rules/drools2_0/"),
DROOLS_ENUM_OLD("drools_old","rules/drools_old/");
假如你是希望学习BPMN,或者想通过集成Camunda来做工作流引擎,那么收藏这篇博客应该就足够了。因为我会介绍BPMN当中最重要的一些元素,而且还附加了完整BPMN设计源文件和Camunda RESTApi的Postman脚本。