相关文章推荐
活泼的骆驼  ·  事务(Azure Synapse ...·  1 年前    · 
魁梧的水煮鱼  ·  IntelliJ IDEA 进行js ...·  1 年前    · 
冷冷的胡萝卜  ·  Vs2017 控制台 ...·  2 年前    · 
飞翔的打火机  ·  Linux 爱好者 - 知乎·  2 年前    · 

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脚本。