Drools7规则引擎教程

  • Drools7规则引擎教程
    • 场景
    • 概述
    • Drools5与Drools7版本变更
    • Drools组成部分
    • API划分
    • Drools7依赖包
    • Drools7 核心API
    • 一个简单的例子
    • kmodule
      • kbase属性
      • ksession的属性
    • KIE
      • KIE的生命周期
    • Fact对象
      • Fact对象的特殊之处
    • API
      • KieService
      • KieContainer
      • KieBase
      • KieSession
      • KieRepository
      • KieProject
      • ClasspathKieProject
    • 有状态Session和无状态Session
      • 有状态session
      • 无状态session
      • 一个无状态的例子
    • 规则文件
      • 规则文件结构
    • Rule语法
    • 属性
      • no-loop详解
      • ruleflow-group
      • lock-on-active
      • salience
      • agenda-group
      • auto-focus
      • activation-group
      • date-effective
      • 定时器
        • 定时器表达式
      • 日历
      • 其他属性规则
    • LHS简介
    • Pattern模式基础用法
    • Pattern模式之List和Map
    • Pattern模式之运算比较符
      • &&和||
      • DRL特殊操作符
      • 运算符优先级
    • RHS
    • 函数
      • insert函数
      • update函数
      • delete函数
      • modify函数
    • 结果条件
    • Query查询
    • Function函数
    • Global全局变量
    • 注释
    • 异常
    • 关键字
      • 硬关键字
      • 软关键字
    • 声明类型
    • 声明类型之继承和枚举
    • 类型声明之API调用
    • 元数据
    • 决策表
      • 初识决策表
      • 决策表编写及编译
      • 决策表实践
      • 决策表配置
        • 全局配置部分
        • RuleTable部分
    • Drools与Springboot集成
      • 依赖包
      • 动态加载规则

Drools7规则引擎教程

场景

  • 风控反洗钱系统
  • 商品折扣系统
  • 积分系统

概述

  • 把复杂冗余的业务规则与系统分离开来,做到架构的可复用、可移植性。

Drools5与Drools7版本变更

Drools是业务规则管理系统(BRMS)解决方案,设计一下项目:

  • Drools Workbench:业务规则管理系统
  • Drools Expert:业务规则引擎
  • Drools Fusion:事件处理
  • jBPM:工作流引擎
  • OptalPlanner:规则引擎

Drools组成部分

  • Drools规则
  • Drools规则的解释执行

API划分

  • 规则编译
  • 规则收集
  • 规则执行

Drools7依赖包

  • kie-api
  • drools-core
  • drools-compile

Drools7 核心API

  • KieServices
  • KieContainer
  • KieSession

一个简单的例子

  • 在resources/META-INF下创建kmodule.xml
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"><kbase name="rules"><ksession name="all-rules"></ksession></kbase>
</kmodule>
  • 在resource/rules下创建drools规则文件goods.drl
package rules
import com.drools.demo.model.Carrule "test-drools7-older than 60"
agenda-group "test-drools7"
when$car: Car(person.age > 60)
then$car.setDiscount(80);System.out.println("test-drools7-older than 60:" + $car.getPerson().getAge());endrule "test-drools-other"
agenda-group "test-drools7"
when$car: Car(person.age < 60)
then$car.setDiscount(60);System.out.println("test-drools-other:" + $car.getPerson().getAge());end
  • 创建Car类
package com.drools.demo.model;import lombok.Data;@Data
public class Car {private int discount = 0;private Person person;
}
  • 创建Person类
package com.drools.demo.model;import lombok.Data;@Data
public class Person {private int age;
}
  • 创建Drools7Test主类
package com.drools.demo.drools;import com.drools.demo.model.Car;
import com.drools.demo.model.Person;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;public class Drools7Test {private static KieSession getKiession() {KieServices kieServices = KieServices.get();KieContainer kieContainer = kieServices.getKieClasspathContainer();KieSession kieSession = kieContainer.newKieSession("all-rules");return kieSession;}/*** 根绝agendaGroup获取该分组下的规则,用于业务规则隔离* @param agendaGroup* @return*/private static KieSession getKiesession(String agendaGroup) {KieSession kieSession = getKiession();//获取agendaGroup并设置焦点kieSession.getAgenda().getAgendaGroup(agendaGroup).setFocus();return kieSession;}public static void main(String... args) {KieSession kieSession = getKiesession("test-drools7");Person person1 = new Person();person1.setAge(65);Car car1 = new Car();car1.setPerson(person1);Person person2 = new Person();person2.setAge(30);Car car2 = new Car();car2.setPerson(person2);kieSession.insert(car1);kieSession.insert(car2);int count = kieSession.fireAllRules();kieSession.dispose();System.out.println(count);System.out.println("car1 discount:" + car1.getDiscount());System.out.println("car2 discount:" + car2.getDiscount());}
}

kmodule

  • kmodule默认路径放在META-INF下(见源码),drools自动解析
  • kmodule中可以包含一个到多个kbase
  • kbase的name要唯一
  • kbase的packages为drl文件所在resources下的路径,注意区分drl文件中的package与此处的packages不一定相同。多个包用逗号隔开。默认情况下扫描resources下面所有规则文件
  • kbase的default属性,标识当前KieBase是不是默认的,如果是默认的则不用名称就可以查找到该KieBase,但每个module最多有一个默认的KieBase
  • kbase下面可以有一个或多个ksession,ksession的name属性必须设置,且必须唯一

kbase属性

属性值 默认值 合法的值 描述
name none any KieBase的名称,这个属性是强制的,必须设置
includes none 逗号分隔的KieBase名称列表 意味着本KieBase将会包含所有的include的KieBase的rule,process定义制品文件,非强制属性
defaule false true/false 表示当前KieBase是不是默认的,如果是默认的,不用名称就可以查找该KieBase,但是每一个KieModule最多只能有一个默认的KieBase
equalsBehavior identity identity,equality 顾名思义就是等于的行为,这个equals是针对fact(事实)的,当插入一个Fact到working memory中的时候,drools引擎会检查该fact是否已经存在,如果存在的话就使用已有的FactHandle,否则就创建新的。而判断Fact是否存在的依据是通过该属性定义的方式来进行的,设置成identity,就是判断对象是否存在,可以理解为用==判断,看是否是同一个对象,如果该属性设置成equality的话,就是通过Fact对象的equals方法来判断
eventProcessingMode cloud cloud,stream 当以云模式编译时,kieBase将事件视为正常事实,而在流模式下允许对其进行时间推理

ksession的属性

属性名 默认值 合法的值 描述
name none any KieSession的名称,该值必须唯一,也是强制的,必须设置
type stateful stateful, stateless 定义该session到底是有状态(statefull)还是无状态(stateless),有状态的session可以利用working memory执行多次,而无状态的则只能执行一次
default false true,false 定义该session是否是默认的,如果是默认的话则可以不用通过session的name来创建session,在同一个module中最多只能有一个默认的session
clockType realtime realtime,pseudo 定义时钟类型,用在事件处理上面,在复合事件处理上会用到,其中realtime表示用的是系统时钟,而pseudo则是用在单元测试时模拟用的
belieSystem simple simple,defeasible,jtms 定义KieSession使用belief system的类型

KIE

  • knowledge is everything

KIE的生命周期

  • 编写:编写规则文件,比如:drl、BPMN2、决策表、实体类等
  • 构建:构建一个可以发布部署的组件,对于KIE来说JAR文件
  • 测试:部署之前对规则进行测试
  • 部署:利用maven仓库将jar部署到应用程序
  • 使用:程序加载jar文件,通过KieContainer对其进行解析创建KieSession
  • 执行:通过KieSession对象的API与Drools引擎进行交互,执行规则
  • 交互:用户通过命令行或者UI与引擎进行交互
  • 管理:管理KieSession或者KieContainer对象

Fact对象

  • Fact对象简单来说就是一个特殊的JavaBean
  • 一般拥有getter/setter方法
  • 放置于WorkingMemory当中
  • 建立应用系统数据和规则的传输桥梁

Fact对象的特殊之处

  • 引用传递——影响应用层的对象
  • FactHandler
        KieSession kieSession = getKiesession(agendaName);Person person = new Person();person.setAge(90);FactHandle handle = kieSession.insert(person);System.out.println(handle.toExternalForm());int count = kieSession.fireAllRules();System.out.println("Fires:" + count);//更新working memory中对象的值,再执行person.setAge(88);kieSession.getAgenda().getAgendaGroup(agendaName).setFocus();kieSession.update(handle, person);count = kieSession.fireAllRules();System.out.println("Fires2:" + count);kieSession.dispose();

API

KieService

  • 提供访问KIE关于构建和运行的相关对象

    • 获取KieContainer,利用KieContainer来访问KBase和KSession等信息
    • 获取KieRepository对象,利用KieRepository来管理KieModule等
  • KieServices就是一个中心,通过它来获取的各种对象来完成规则构建、管理和执行等操作

KieContainer

  • KieContainer就是一个KieBase的容器,提供获得KieBase的方法
  • KieContainer的方法内部依旧通过KieBase来创建KieSession

KieBase

  • 一个知识仓库,包含了若干的规则、流程、方法等
  • KieBase本身并不包含运行时的数据之类的,如果需要执行规则KieBase中的规则的话,就需要根据KieBase创建KieSession

KieSession

  • 基于KieBase创建,与Drools引擎打交道的会话

KieRepository

  • KieRepository是一个单例对象,它是存放KieModule的仓库,KieModule由kmodule.xml文件定义

KieProject

  • KieContainer通过KieProject来初始化、构造KieModule,并将KieModule存放在KieRepository中,然后KieContainer可以通过KieProject来查找KieModule定义的信息,并根据这些信息构造KieBase和KieSession

ClasspathKieProject

  • ClasspathKieProject实现了KieProject接口,它提供了根据类路径中的META-INF/kmodule.xml文件构造KieModule的能力,是基于maven构造Drools组件的基本保障之一。意味着只要按照前面提到过的maven工程结构组织我们的规则文件或流程文件,只用很少的代码完成模型的加载和构建。

有状态Session和无状态Session

有状态session

  • 通过KieContainer可以获取KieSession,在kmodule.xml配置文件中如果不指定ksession的type默认也是有状态的session。
  • 有状态的session的特性是:我们可以通过建立一次session完成多次与规则引擎之间的交互,在没有调用dispose的一般步骤为:获取session,insert fact对象,然后调用fireAllRules进行规则匹配,随后调用dispose方法关闭session
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"><kbase name="rules"><ksession name="all-rules" type="stateful"></ksession></kbase>
</kmodule>

无状态session

  • StatelessKieSession提供了一个更加便利的API,是对KieSession的封装,不再调用dispose方法进行session的关闭。
  • 它隔离了每次与规则引擎的交互,不会再去维护会话的状态。
  • 不再提供fireAllRules方法
  • 使用场景
    • 数据校验
    • 运算
    • 数据过滤
    • 消息路由
    • 任何能被描述成函数或公式的规则

一个无状态的例子

kmodule.xml

<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"><kbase name="rules" packages="rules"><ksession name="all-rules" type="stateful"></ksession></kbase><kbase packages="stateless"><ksession name="stateless-rules" type="stateless"></ksession></kbase>
</kmodule>

resources/stateless/stateless.drl

package stateless
import com.drools.demo.Personrule "test-stateless"when$p:Person()
thenSystem.out.println($p.getAge());end

BaseKieSession.java

package com.drools.demo.kie;import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.StatelessKieSession;public class BaseKieSession {protected KieSession getKiesessionByName(String sessionName){KieServices kieServices = KieServices.get();KieContainer kieContainer = kieServices.getKieClasspathContainer();KieSession kieSession = kieContainer.newKieSession(sessionName);return kieSession;}protected KieSession getKiesession(){KieServices kieServices = KieServices.get();KieContainer kieContainer = kieServices.getKieClasspathContainer();KieSession kieSession = kieContainer.newKieSession("all-rules");return kieSession;}protected KieSession getKiesession(String agendaName){KieSession kieSession = getKiesession();kieSession.getAgenda().getAgendaGroup(agendaName).setFocus();return kieSession;}protected StatelessKieSession getStatelessKiesession(){KieServices kieServices = KieServices.get();KieContainer kieContainer = kieServices.getKieClasspathContainer();StatelessKieSession kieSession = kieContainer.newStatelessKieSession("stateless-rules");return kieSession;}protected StatelessKieSession getStatelessKiesession(String agendaName){StatelessKieSession kieSession = getStatelessKiesession();
//        kieSession.getAgenda().getAgendaGroup(agendaName).setFocus();return kieSession;}
}

StatelessSessionTest.java

package com.drools.demo.test.chapter5;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.StatelessKieSession;import java.util.ArrayList;
import java.util.List;public class StatelessSessionTest extends BaseKieSession {@Testpublic void createTest(){StatelessKieSession kieSession = getStatelessKiesession();Person person = new Person();person.setAge(35);kieSession.execute(person);List<Person> personList = new ArrayList<>();personList.add(person);kieSession.execute(personList);}
}

规则文件

  • 标准的规则文件是以“.drl”结尾的文本文件
  • 可以存放用户自定义的函数、数据对象及自定义查询等

规则文件结构

  • package——不需要与物理路径一致,只是用来区分不同业务,package name
  • import——import static,import function
  • globals——定义全局方法函数
  • functions
  • queries
  • rule

Rule语法

  • rule “name”–规则名称
  • attributes–属性
  • when——LHS Left Hand Side,多个条件默认用and,也可以使用or
  • then——RHS Right Hand Side
  • end
    一个最简单的规则
rule "name"
when
then
end

属性

no-loop详解

  • 定义当前的规则是否允许多次循环执行,默认是false
  • 当执行update,insert,retract,modify等操作时,会循环执行规则
  • 通过设置no-loop属性为true来避免死循环
package noloopimport com.drools.demo.Personrule "test-no-loop-rule"
//no-loop false
no-loop true
when$p:Person(age > 10)
then$p.setAge(11);System.out.println($p.getAge());update($p);end

ruleflow-group

  • 在使用规则流的时候要用到ruleflow-group属性,该属性的值为一个字符串,作用是将规则划分为一个个的组,然后在规则流当中通过使用ruleflow-group属性的值,从而使用对应的规则
  • 从drools6.5版本的说明文档到drools7版本的说明文档中都提到ruleflow-group和agenda-group进行合并,返回相同的底层数据结构
  • 必须设置了焦点才能执行
  • 设置焦点是一次性的,设置过焦点之后再次运行焦点就会失效,不会被执行
    kbase.xml
    <kbase name="ruleFlowGroup-rules" packages="rowflowGroup"><ksession name="ruleFlowGroup-rules"></ksession></kbase>

ruleflowGroup.drl

package rowflowGrouprule "test-rule-flow-group-1"
ruleflow-group "rule-flow-group-1"
when
thenSystem.out.println("rule-flow-group-1 被触发了");endrule "test-rule-flow-group-2"
ruleflow-group "rule-flow-group-2"
when
thenSystem.out.println("rule-flow-group-2 被触发了");end

RowFlowGroupTest.java

package com.drools.demo.test;import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class RowFlowGroupTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("ruleFlowGroup-rules");//agenda-group和rowflow-group作用一样kieSession.getAgenda().getAgendaGroup("rule-flow-group-1").setFocus();kieSession.fireAllRules();kieSession.getAgenda().getAgendaGroup("rule-flow-group-2").setFocus();kieSession.fireAllRules();kieSession.getAgenda().getAgendaGroup("rule-flow-group-1").setFocus();kieSession.fireAllRules();kieSession.getAgenda().getAgendaGroup("rule-flow-group-2").setFocus();kieSession.fireAllRules();kieSession.dispose();}}

lock-on-active

  • 避免因FACT对象被更新使得执行过的规则被再次执行
  • 触发此类规则的操作有update,retract,modify等
  • 拥有no-loop的功能,同时又能避免其他规则改变FACT对象导致规则重新执行
  • 设置为true,则不会触发执行
    kbase.xml
    <kbase name="lock-on-active" packages="lockOnActive"><ksession name="lock-on-active"></ksession></kbase>

lockOnActive.drl

package lockOnActiveimport com.drools.demo.Personrule "test-lock-on-active-1"when$p: Person(age < 20)
thenSystem.out.println("test-lock-on-active-1 被触发,age=" + $p.getAge());$p.setAge(21);update($p)endrule "test-lock-on-active-2"lock-on-active true
when$p: Person(age >= 20)
thenSystem.out.println("test-lock-on-active-2 被触发,age=" + $p.getAge());end

LockOnActiveTest.java

package com.drools.demo.test;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;import java.lang.reflect.Field;public class LockOnActiveTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("lock-on-active");Person person = new Person();person.setAge(19);kieSession.insert(person);kieSession.fireAllRules();kieSession.dispose();}
}

salience

  • 用来设置规则执行的优先级
  • salience属性的值是一个数字,数字越大优先级越高,可以是负数
  • 默认是0
  • 如果不设置salience,则执行是随机的
  • salience可以被动态赋值

kmodule.xml

    <kbase name="salience-rules" packages="salienceTest"><ksession name="salience-rules"></ksession></kbase>

salience.drl

package salienceTestimport com.drools.demo.Personrule "salience1"
salience 0
when
thenSystem.out.println("salience1被执行");endrule "salience2"
salience 1
when
thenSystem.out.println("salience2被执行");end//动态赋值,把age复制给变量sal
rule "salience3"
salience sal
when$p: Person(sal: age)
thenSystem.out.println("salience3执行");end

SalienceTest.java

package com.drools.demo.test;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class SalienceTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("salience-rules");Person person = new Person();person.setAge(10);kieSession.insert(person);kieSession.fireAllRules();kieSession.dispose();}
}

agenda-group

  • agenda-group基本作用
  • 对规则进行分组
  • 设置焦点
package agendaGrouprule "test-agenda-group-1"
agenda-group "agenda-group-test"
when
thenSystem.out.println("agenda-group-1被触发");endrule "test-agenda-group-2"
agenda-group "agenda-group-test"
when
thenSystem.out.println("agenda-group-2被触发");endrule "test-agenda-group-3"
agenda-group "agenda-group-test3"
when
thenSystem.out.println("agenda-group-3被触发");end

auto-focus

  • 对agenda-group和ruleflow-group的补充
  • 默认false
  • 设置为true,自动获取焦点

autoFocus.drl

package autoFocusrule "test-auto-fucos-1"agenda-group "auto-focus-1"
auto-focus false
when
thenSystem.out.println("auto-focus-1 被触发");endrule "test-auto-fucos-2"agenda-group "auto-focus-2"
auto-focus true
when
thenSystem.out.println("auto-focus-2 被触发");end

activation-group

  • 该属性将若干个规则划分成一个组,统一命名默认false
  • 具有相同activation-group属性的规则中只要又一个被执行,其他的规则都不再执行
  • 该属性以前也被成为异或(Xor)组
package activationGrouprule "test-activation-group=1"
activation-group "activation-group"
when
thenSystem.out.println("activation 1 被触发");endrule "test-activation-group=2"
activation-group "activation-group"
salience 1
when
thenSystem.out.println("activation 2 被触发");end

date-effective

  • 该属性是用来控制规则只有在到达指定时间后才会触发(生效时间)
  • 与系统当前时间进行比对,大于等于系统时间会执行
  • 默认date-effective的日期格式为"dd-MMM-yyyy"
  • 可自定义格式
  • 对照属性date-expire,用法和date-effective一样,只不过是失效时间

dateEffective.drl

package dateEffectiverule "test-date-effective-1"
//date-effective "16-Mar-2021"
date-effective "2021-03-17 21:00"
when
thenSystem.out.println("test-date-effective-1 被触发了");endrule "test-date-effective-2"
when
thenSystem.out.println("test-date-effective-2 被触发了");end

DateEffectiveTest.java

package com.drools.demo.test;import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class DateEffectiveTest extends BaseKieSession {@Testpublic void createTest(){System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm");KieSession kieSession = getKiesessionByName("dateEffective-rules");kieSession.fireAllRules();kieSession.dispose();}
}

定时器

  • 基于interval(间隔)和cron表达式
  • 间隔定时器用int来定义,它遵循java.util.Timer对象的使用方法
  • Cron定时器用cron来定义,使用标准的Unix cron表达式

定时器表达式

  • timer(int:?)
  • timer(int:30s)
  • timer(int:30s 5m)
  • timer(cron:)
  • timer(cron:* 0/15 * * * ?)

Server.java

package com.drools.demo;import lombok.Data;@Data
public class Server {private int times;private String result;
}

timer.drl

package timerTest
import com.drools.demo.Server
import java.util.Daterule "test-timer"timer (cron:* 0/1 * * * ?)when$s:Server(times > 5)
thenSystem.out.println("已经尝试" + $s.getTimes() + "次,超过预警次数");$s.setResult(new Date() + "-服务器已经尝试" + $s.getTimes() + "次,依旧失败,发出警告");end

TimerTest.java

package com.drools.demo.test;import com.drools.demo.Server;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;public class TimerTest extends BaseKieSession {@Testpublic void createTest() throws Exception{KieSession kieSession = getKiesessionByName("timerTest-rules");Server server = new Server();server.setTimes(0);new Thread(()->{//一直阻塞,直到等待到halt()kieSession.fireUntilHalt();}).start();FactHandle factHandle = kieSession.insert(server);for (int i=1;i<10;i++){Thread.sleep(1000);server.setTimes(i);kieSession.update(factHandle, server);}Thread.sleep(3000);kieSession.halt();System.out.println("server尝试结果:" + server.getResult());}
}

日历

  • 日历可以单独应用于规则中,也可以和timer结合使用在规则中使用。
  • 通过属性calendars来定义日历
  • 可以和timer配合使用
  • 适用希望在哪天触发的场景

添加quartz依赖

     <dependency><groupId>org.opensymphony.quartz</groupId><artifactId>quartz</artifactId><version>1.6.1</version></dependency>

calendar.drl

package calendarTestrule "test-calendar-rule1"
calendars "weekday"
when
thenSystem.out.println("test-calendar-rule1 被触发");endrule "test-calendar-rule2"
calendars "weekday_exclude"
when
thenSystem.out.println("test-calendar-rule2 被触发");end

CalendarTest.java

package com.drools.demo.test;import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.time.Calendar;
import org.quartz.impl.calendar.WeeklyCalendar;public class CalendarTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("calendarTest-rules");kieSession.getCalendars().set("weekday", WEEKDAY);kieSession.getCalendars().set("weekday_exclude", WEEKDAY_EXCLUDE);kieSession.fireAllRules();kieSession.dispose();}private static final Calendar WEEKDAY = new Calendar(){@Overridepublic boolean isTimeIncluded(long timestamp) {WeeklyCalendar weeklyCalendar = new WeeklyCalendar();weeklyCalendar.setDaysExcluded(new boolean[]{false, false, false, false, false, false, false});weeklyCalendar.setDayExcluded(java.util.Calendar.WEDNESDAY, true);//排除掉今天星期三return weeklyCalendar.isTimeIncluded(timestamp);}};private static final Calendar WEEKDAY_EXCLUDE = new Calendar(){@Overridepublic boolean isTimeIncluded(long timestamp) {WeeklyCalendar weeklyCalendar = new WeeklyCalendar();weeklyCalendar.setDaysExcluded(new boolean[]{false, false, false, false, false, false, false});return weeklyCalendar.isTimeIncluded(timestamp);}};
}

其他属性规则

  • dialect:要使用的语言类型,Java,mvel
  • duration:已废弃,规则将指定的时间之后在另外一个线程里触发
  • enabled:设置规则是否可用,true:可用,false:不可用
dialect "java"
dialect "mvel"

LHS简介

  • LHS是规则条件部分的统称,由0个或多个条件元素组成
  • 如果没有条件元素那么默认就是true
  • 多个跳进默认是“和”的关系
  • and不具有优先绑定功能
package lhs
import com.drools.demo.model.Personrule "test-lhs-rule"
when
//    eval(true)$p1: Person(age > 10)
//    or
//    and$p2: Person(age > 20)
thenSystem.out.println("规则被触发");end
KieSession kieSession = getKieSessionByName("lhs-rules");Person person1 = new Person();person1.setAge(50);Person person2 = new Person();person2.setAge(30);kieSession.insert(person1);kieSession.insert(person2);kieSession.fireAllRules();kieSession.dispose();

Pattern模式基础用法

  • Pattern语法 patternBinding:patternType(“constraints”)
  • 任何一个JavaBean中的属性都可以访问,不过对应的属性要提供getter方法
  • 在pattern的约束条件中,可以任何返回结果为布尔类型的Java表达式
  • Java表达式也可以和增强的表达式进行结合使用,比如属性访问,可以通过使用括号来更改计算优先级,如在任一逻辑或数学表达式中
  • 逗号分隔符,逗号可以对约束条件进行分组,它的作用相当于“AND”
    $p: Person(age % 10 == 0, name == "zhangsan")
  • 变量的绑定
when$p: Person($age: age)
thenSystem.out.println($age);end
  • 内部类分组访问——访问一个内部类的多个属性
    $c: Car(discount < 8, person,(age == < 10, name != ""))
  • 内部强制转换
    //subPerson强制转换成Person$c : Car(subPerson#Person.age == 10)
  • 日期字符——规则语法中除了支持Java标准字符,同时也支持日期字符。drools默认支持的日期格式为“dd-mmm-yyyy”,可以通过设置系统变量“drools.dateformat”的值来改变默认的日期格式
$p: Person(birthday > "3-Nov-2017")

Pattern模式之List和Map

  • Person(childList[0].age == 10)
  • Person(credetialMap[“jsmith”].valid)
package rules
import java.util.Map
import java.util.List
import com.drools.demo.model.Personrule "map-and-list-rule"when
//    $map: Map()
//    $map: Map(this["a"] == 1)$list: List()$p: Person(age == 20) from $list
then
//    System.out.println("a=" + $map.get("a"));
//    System.out.println("b=" + $map.get("b"));
//    System.out.println("person list:" + ((Person)$list.get(0)).getAge());System.out.println("person list:" + ((Person)$p).getAge());end
public class ListAndMapTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKieSessionByName("all-rules");Map<String, Integer> map = new HashMap<>();map.put("a", 1);map.put("a", 2);List<Person> list = new ArrayList<>();Person person = new Person();person.setAge(18);list.add(person);Person person1 = new Person();person1.setAge(20);list.add(person1);kieSession.insert(map);kieSession.insert(list);kieSession.fireAllRules();kieSession.dispose();}
}

Pattern模式之运算比较符

&&和||

  • Person(age > 20 && < 40)
  • Person(age((>30 && <40) || (>20 && < 25)))
  • Person(age > 30 && < 40 || location == “london”)

DRL特殊操作符

  • < > >=
  • !. 非空校验
    • Person($streetName : address!.street)——address非空的时候取street赋值给streetName
  • matches操作符(正则表达式)
    • Cheese(type matches “(Buffalo)?\S*Mozzarella”)
  • contains操作符
  • memberOf——用来检查前面对象是否符合后面集合
    • CheeseCounter(cheese memberOf $matureCheeses)

运算符优先级

操作类型 操作符 备注
(嵌套/空安全)属性访问 .!. 非标准Java语义
List/Map访问 [] 非标准Java语义
约束绑定 : 非标准Java语义
乘除 */%
加减 ±
移位 <<>>>>>>
关系 <>>=instanceof
==!= 未使用标准Java语义,某些语义相当于equals
非短路AND &
非短路异或 ^
非短路包含 OR
逻辑与 &&
逻辑或 ||
三元运算符 ?:
逗号分隔, 相当于and , 非标准Java语义

RHS

  • RHS是满足LHS条件之后进行后续处理部分的统称
  • 保持RHS的精简和可读性
  • 主要功能是对working memory中的数据进行insert、update、delete或modify操作

函数

insert函数

  • drl中insert函数和调用KieSession中的方法效果一样
  • 调用insert之后,规则会进行重新匹配,如果没有no-loop为true或lock-on-active为true的规则,如果条件满足则会重新执行
package rules
import com.drools.demo.model.Personrule "test-insert-rule"when
thenSystem.out.println("规则被触发");Person person = new Person();person.setAge(27);insert(person);end

update函数

  • update函数可对Working Memory中的Fact对象进行更新变更操作,与StatefulSession中的update的作用基本相同
  • 查看KnowledgeHelper接口中的update方法可以发现,update函数由多种参数组合的使用方法
  • 在实际使用中更多的会传入FACT对象来进行更新操作

update.drl

package updates
import com.drools.demo.Personrule "update-demo-rule-1"
salience 2
when$p: Person(age == 24);
thenSystem.out.println("update-demo-rule-1 规则被触发");
//    $p.setAge(25);
//    update($p);endrule "update-demo-rule-2"
salience 1
when$p: Person(age == 25)
thenSystem.out.println("update-demo-rule-2 规则被触发");System.out.println("person.age=" + $p.getAge());end

UpdateTest.java

package com.drools.demo.test;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;public class UpdateTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("updates-rules");Person person = new Person();person.setAge(24);FactHandle factHandle = kieSession.insert(person);//        kieSession.fireAllRules();person.setAge(25);kieSession.update(factHandle, person);kieSession.fireAllRules();kieSession.dispose();}
}

delete函数

  • delete函数可对working memory中的FACT对象进行删除操作,与StatefulSession中的delete的作用i本想相同
  • 与retract方法效果一样,但已废弃
    delete.drl
package deletes
import com.drools.demo.Personrule "delete-demo-rule-1"
salience 2
when$p: Person(age == 24);
thenSystem.out.println("update-demo-rule-1 规则被触发");delete($p);endrule "delete-demo-rule-2"
salience 1
when$p: Person(age == 24)
thenSystem.out.println("update-demo-rule-2 规则被触发");end

DeleteTest.java

package com.drools.demo.test;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;public class DeleteTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("deleteDemo-rules");Person person = new Person();person.setAge(24);FactHandle factHandle = kieSession.insert(person);kieSession.delete(factHandle);kieSession.delete(factHandle, FactHandle.State.LOGICAL);kieSession.fireAllRules();kieSession.dispose();}
}

modify函数

  • modify是基于结构化的更新操作,它将更新操作与设置属性相结合,用来更改Fact对象的属性
modify(<fact-expression>){<expression>[,<expression>]*
}

modify.drl

package modifyTest
import com.drools.demo.Personrule "modify-demo-rule-1"
salience 2
when$p: Person(age == 21);
thenSystem.out.println("modify-demo-rule-1 规则被触发");modify($p){setAge(22)}endrule "modify-demo-rule-2"
salience 1
when$p: Person(age == 22)
thenSystem.out.println("modify-demo-rule-2 规则被触发");end

ModifyTest.java

package com.drools.demo.test;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class ModifyTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("modify-rules");Person person =  new Person();person.setAge(21);kieSession.insert(person);kieSession.fireAllRules();kieSession.dispose();}
}

结果条件

  • 在Java中,如果有重复的代码我们会考虑进行重构,抽取公共方法或集成父类,以减少相同的代码在多处出现,达到代码的最优管理和不必要的麻烦
  • 有条件的结果
  • Drools规则的继承
  • do和标记
  • LHS中的if判断

condition.drl

package conditions
import com.drools.demo.Person
import com.drools.demo.Carrule "condition-demo-rule-1"
no-loop true
when$p: Person(age > 18)if(age == 20) do[updatePerson1]else do[updatePerson2]
thenSystem.out.println("condition-demo-rule-1 规则被触发");
then[updatePerson1]System.out.println("执行updatePerson1");modify($p){setAge(17)}
then[updatePerson2]System.out.println("执行updatePerson2");modify($p){setAge(20)}endrule "condition-demo-rule-2"extends "condition-demo-rule-1"
when
//    $p: Person(age > 18)$c: Car(discount < 90)
thenSystem.out.println("condition-demo-rule-2 规则被触发");end

ConditionTest.java

package com.drools.demo.test;import com.drools.demo.Car;
import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class ConditionTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("condition-rules");Person person =  new Person();person.setAge(19);Car car = new Car();car.setDiscount(80);kieSession.insert(person);kieSession.insert(car);kieSession.fireAllRules();kieSession.dispose();}
}

Query查询

  • Query语法提供了一种查询working memory中符合约束条件的FACT对象的简单方法
  • 仅包含规则文件中的LHS部分,不用指定“when”和“then”部分
  • Query有一个可选参数集合,每一个参数都有可选的类型,如果没有指定类型,则默认为Object类型
  • Query名称需要全局唯一
  • 使用kieSession.getQueryResults(“name”)方法可以获得查询的结果

query.drl

package querys
import com.drools.demo.Personrule "query-demo-rule-1"
when$p: Person(age == 20);
thenSystem.out.println("Name is " + $p.getName());System.out.println("query-demo-rule-1 规则被触发");endquery "query-by-age"$p1 : Person(age == 23)
endquery "query-by-param" (Integer ageParam)$p2 : Person(age >= ageParam)
end

QueryTest.java

package com.drools.demo.test;import com.drools.demo.Person;
import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;public class QueryTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("query-rules");Person person1 =  new Person();person1.setAge(20);person1.setName("zhangsan");Person person2 = new Person();person2.setAge(23);person2.setName("lisi");kieSession.insert(person1);kieSession.insert(person2);kieSession.fireAllRules();QueryResults queryResults1 = kieSession.getQueryResults("query-by-age");System.out.println(queryResults1.size());for (QueryResultsRow row : queryResults1) {Person person = (Person) row.get("$p1");System.out.println("Person1 name is: " + person.getName());}System.out.println("--------------------------------");QueryResults queryResults2 = kieSession.getQueryResults("query-by-param", 20);System.out.println(queryResults2.size());for (QueryResultsRow row : queryResults2) {Person person = (Person) row.get("$p2");System.out.println("Person2 name is: " + person.getName());}kieSession.dispose();}
}

Function函数

  • 相当于Java中的方法,编译器会生成相应的辅助类
  • 封装多处都调用的业务逻辑到一个方法中
  • 函数的参数和结果数据类型与Java一致

function.drl

package functions
import com.drools.demo.Personrule "functions-demo-rule-1"
when
thenSystem.out.println("functions-demo-rule-1 规则被触发");helloFunction();System.out.println(paramFunction("Tom"));endfunction void helloFunction(){System.out.println("hello drools function");
}function String paramFunction(String name){return "Hello " + name + "!";
}

FunctionTest.java

package com.drools.demo.test;import com.drools.demo.kie.BaseKieSession;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class FunctionTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("function-rules");kieSession.fireAllRules();kieSession.dispose();}
}

Global全局变量

  • global用来定义全局变量,它可以让应用程序的对象在规则文件中能够被访问
  • 可以用来为规则文件提供数据或服务
  • 可以用来操作规则执行结果的处理和从规则返回数据,比如执行结果的日志或值,或者与应用程序进行交互的规则的回调处理
  • 全局变量并不会被插入到working memory中,因此,除非作为常量值,否则不应该将全局变量于规则约束的判断中
  • 如果多个包中声明具有相同标识符的全局变量,则必须是相同的类型,并且他们都将引用相同的全局值

EmailService.java

package com.drools.demo.service;public class EmailService {//    public static void sendEmail(){public void sendEmail(){System.out.println("Email has be send.");}
}

global.drl

package globals
import com.drools.demo.Personglobal com.drools.demo.service.EmailService emailServicerule "globals-demo-rule-1"
when
thenSystem.out.println("globals-demo-rule-1 规则被触发");emailService.sendEmail();end

GlobalTest.java

package com.drools.demo.test;import com.drools.demo.kie.BaseKieSession;
import com.drools.demo.service.EmailService;
import org.junit.Test;
import org.kie.api.runtime.KieSession;public class GlobalTest extends BaseKieSession {@Testpublic void createTest(){KieSession kieSession = getKiesessionByName("global-rules");EmailService emailService = new EmailService();kieSession.setGlobal("emailService", emailService);kieSession.fireAllRules();kieSession.dispose();}
}

注释

  • drl文件中的注释与Java的注释方法一样
  • 通过//进行注释
  • 通过/*注释内容*/进行注释

异常

  • drools5引入了标准化的错误信息,可以快速的查找和解决问题
  • 异常分两类,一类为普通的异常,一类为规则特有的异常格式

关键字

  • Drools5开始引入了硬关键字和软关键字

硬关键字

  • 硬关键字是保留关键字,在命名demo对象,属性,方法,函数和规则文本中使用的其他元素时,不能使用任何硬编码关键字

    • true
    • false
    • null

软关键字

  • 软关键字只在它们的上下文中被识别,可以在其他地方使用这些词,建议避免

    • 属性
    • 语法关键字(package, import, when, then等)
    • 条件判断等
    • lock-on-active, date-effective, date-expires, no-loop, auto-focus, activation-group, agenda-group, ruleflow-group, entry-point, duration, package, import, dialect, salience, enabled, attributes, rule, extend, when, then, template, query, declare, function, global, eval, not, in, or, and, exists, forall, accumulate, collect, from, action, reverse, result, end, over, init

声明类型

  • 适用于直接定义规则引擎的数据原型,不用再在Java中创建
  • 新构建扩展原型
    示例:
declare Addressnumber:intstreetName:Stringcity:String
end

newType.drl

package newTypes
import java.util.Daterule "newtype-demo-rule"
when
thenAddress address = new Address();address.setCity("nanjing");address.setNumber(111);insert(address);enddeclare Addressnumber: Integercity: StringcreateTime: Date
end

声明类型之继承和枚举

  • 支持继承extends
  • 支持枚举
package rules
import java.util.Daterule "new_type_rule0"
when
thenAddress address = new Address();address.setName("中国");address.setCity("北京");address.setNumber(111);insert(address)endrule "new_type_rule"when$address: Address(name == CountryName.CHINA.getFullName())
thenSystem.out.println("规则被触发");enddeclare Address extends Countrynumber: Integercity: StringcreateTime: Date
enddeclare Countryname: String
enddeclare enum CountryNameCHINA("中国");fullName: String
end

类型声明之API调用

  • 在drl文件中声明的类型可以通过API的方式在代码中进行调用赋值
    NewTypeTest.java
package com.drools.demo.test;import com.drools.demo.kie.BaseKieSession;
import com.drools.demo.model.Person;
import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.definition.type.FactType;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;public class NewTypeTest extends BaseKieSession {@Testpublic void createTest() throws Exception{KieContainer kieContainer = getKieContainer();KieBase kieBase = kieContainer.getKieBase("newType-rules");FactType factType = kieBase.getFactType("com.newType", "Country");Object country = factType.newInstance();factType.set(country, "name", "美国");KieSession kieSession = getKieSessionByName("newType-rules");kieSession.fireAllRules();kieSession.dispose();}
}

元数据

  • 描述数据属性的数据
  • 元数据的作用:定义数据,描述数据等
  • Drools声明元数据
package rules
import com.drools.demo.model.Person
import rules.Cityrule "test-meta-rule"
when
thenCity city = new City();city = new City("北京");city = new City("北京","中国");System.out.println("test-meta-rule 规则被触发");enddeclare City@author("zzz")name: String @keyaddress: String
end

@author是没有实际意思的元数据
@key是有限制的元数据

决策表

初识决策表

  • 决策表是一个“精确而紧凑的”表示条件逻辑的方式,非常适合商业级别的规则
  • 支持xls和csv格式的文件
  • 什么时候用决策表
    • 规则能够被表达为指定格式模板+数据的格式,考虑使用决策表
    • 很少量的规则不建议使用决策表
    • 不是遵循一组规则模板的规则也不建议是使用决策表

决策表编写及编译

  • 决策表格式

    • RuleSet 类似package
    • Squential 优先级定义
    • Functions 方法函数
    • 空行
    • RuleTable 定义规则,类似rulename
    • Condition 条件,就是LHS里的判断条件
  • 决策表加载

        <dependency><groupId>org.drools</groupId><artifactId>drools-decisiontables</artifactId><version>7.48.0.Final</version></dependency>
  • 使用SpreadsheetCompiler类进行编译

  • 推荐使用Excel2009,xls格式

决策表实践

决策表配置

全局配置部分

  • RuleSet:定义包名
  • Import:指定导入的class,包括类方法
  • Variables:指定全局变量
  • Notes:输入任何内容
  • Functions:本地方法

RuleTable部分

  • CONDITION:指定单个规则的条件,条件不写的话默认就是==
  • ACTION:指定rule的结果
  • PRIORITY:指定rule的salience属性
  • No-loop:指定rule的no-loop属性
关键字 说明 是否必须
RuleSet 在这个单元格内容和drl文件中的package是一样 必须,只能有一个(如果为空,则使用默认值)
Sequential 右边的单元可以是true或False,如果是true则确保规则按照从表格的上面到下面的顺序执行(规则是从上到下,如果是false就是乱序) 可选
Import 要导入规则库中的类的列表 可选
Functions 紧接右边的单元格可以包含函数,其可用于规则的片段中。drools支持在drl中定义函数,允许逻辑被嵌入在规则中,不用硬编码改变,小心使用,语法与标准DRL相同 可选
Variables 紧跟在右边的单元格包含global声明,格式是类型跟着变量名与DRL中的global一个意思 可选
Queries 紧接右边的单元格可以包含Drools支持的全局声明,它一个类型,紧跟着一个查询名字与drl中的query是一个意思 可选
RuleTable 这个的意思是表示规则名,写法是在RuleTable后直接写规则名,不用另写一列 必选
CONDITION 指明该列被用于规则条件CONDITION相当于drl中的when 每个规则表至少一个
ACTION 指明该列将被用于推论,简单理解为结果,相当于drl中r then ACTION 与CONDITION是平行的 每个规则表至少一个
PRIORITY 指明该列的值将被设置为该规则行的salience值 可选
DURATION 指明该列的值将被设置为该规则的期限duration 可选
NAME 指明该列的值将被设置为从那行产生的规则名字 可选
NO-LOOP 指明这个规则不允许循环 可选
ACTIVATION-GROUP 在这个列中的单元格的值,指出该规则行属于特定的XOR活动组 可选
AGENDA-GROUP 在这个列中的单元格的值,指出该规则行属于特定的议程组,可以理解成获取焦点 可选
RULEFLOW-GROUP 在这个列中的单元格的值,指出该规则行属于特定的规则流组 可选

Drools与Springboot集成

依赖包

<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><spring.version>2.3.2.RELEASE</spring.version><drools.version>7.0.0.Final</drools.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><type>pom</type><version>${spring.version}</version><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
<!--        <dependency>-->
<!--            <groupId>mysql</groupId>-->
<!--            <artifactId>mysql-connector-java</artifactId>-->
<!--        </dependency>--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>org.kie</groupId><artifactId>kie-spring</artifactId><version>${drools.version}</version><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.3.2</version></dependency>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-actuator</artifactId>-->
<!--            <version>1.2.3.RELEASE</version>-->
<!--        </dependency>--></dependencies>

动态加载规则

  • 第一种:KieHelper的reload方式,reloadByHelper
  • 第二种:KieFileSystem重新加载,reload

DroolsAutoConfiguration.java

package com.demo.drools.config;import com.demo.drools.utils.KieUtils;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;@Configuration
public class DroolsAutoConfiguration {private static final String RULES_PATH = "rules/";@Bean@ConditionalOnMissingBean(KieFileSystem.class)public KieFileSystem kieFileSystem() throws Exception{KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();for (Resource file: getRuleFiles()){kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));}return kieFileSystem;}@Bean@ConditionalOnMissingBean(KieContainer.class)public KieContainer kieContainer() throws Exception{KieServices kieServices = getKieServices();final KieRepository kieRepository = kieServices.getRepository();kieRepository.addKieModule(new KieModule() {@Overridepublic ReleaseId getReleaseId() {return kieRepository.getDefaultReleaseId();}});KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());Results results = kieBuilder.getResults();if (results.hasMessages(Message.Level.ERROR)){System.out.println(results.getMessages());throw new IllegalStateException("### errors ###");}kieBuilder.buildAll();KieContainer kieContainer = kieServices.newKieContainer(kieRepository.getDefaultReleaseId());KieUtils.setKieContainer(kieContainer);return kieContainer;}@Bean@ConditionalOnMissingBean(KieBase.class)public KieBase kieBase() throws Exception{return kieContainer().getKieBase();}@Bean@ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)public KModuleBeanFactoryPostProcessor kiePostProcessor(){return new KModuleBeanFactoryPostProcessor();}private Resource[] getRuleFiles() throws Exception{ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");}private KieServices getKieServices(){return KieServices.Factory.get();}
}

ReloadDroolsRules.java

package com.demo.drools.component;import com.demo.drools.utils.KieUtils;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.utils.KieHelper;
import org.springframework.stereotype.Component;import java.io.UnsupportedEncodingException;@Component
public class ReloadDroolsRules {private String loadRules(){//从数据库加载规则return "package plausibcheck.adress\n\n rule \"Postcode 6 numbers\"\n\n    when\n  then\n        System.out.println(\"规则2中打印日志:校验通过!\");\n end";}private KieServices getKieServices(){return KieServices.Factory.get();}public void reload() throws UnsupportedEncodingException {KieServices kieServices = getKieServices();KieFileSystem kfs = kieServices.newKieFileSystem();kfs.write("src/main/resources/rules/temp.drl", loadRules());KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();Results results = kieBuilder.getResults();if (results.hasMessages(Message.Level.ERROR)){System.out.println(results.getMessages());throw new IllegalStateException("### errors ###");}KieUtils.setKieContainer(kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()));System.out.println("reload新规则重载成功");}public void reloadByHelper() throws UnsupportedEncodingException{KieHelper kieHelper = new KieHelper();kieHelper.addContent(loadRules(), ResourceType.DRL);Results results = kieHelper.verify();if (results.hasMessages(Message.Level.ERROR)){throw new IllegalStateException("### errors ###");}KieContainer kieContainer = kieHelper.getKieContainer();KieUtils.setKieContainer(kieContainer);System.out.println("新规则重载成功");}
}

KieUtils.java

package com.demo.drools.utils;import org.kie.api.runtime.KieContainer;public class KieUtils {private static KieContainer kieContainer;public static KieContainer getKieContainer(){return kieContainer;}public static void setKieContainer(KieContainer kieContainer){KieUtils.kieContainer = kieContainer;}
}

TestController.java

package com.demo.drools.controller;import com.demo.drools.component.ReloadDroolsRules;
import com.demo.drools.model.Address;
import com.demo.drools.model.fact.AddressCheckResult;
import com.demo.drools.utils.KieUtils;
import org.kie.api.runtime.KieSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.io.IOException;@RestController
@RequestMapping("/test")
public class TestController {@Resourceprivate ReloadDroolsRules reloadDroolsRules;@ResponseBody@RequestMapping("/address")public void test(){KieSession kieSession = KieUtils.getKieContainer().newKieSession();Address address = new Address();address.setPostcode("994251");AddressCheckResult result = new AddressCheckResult();kieSession.insert(address);kieSession.insert(result);int ruleFiredCount = kieSession.fireAllRules();System.out.println("触发了" + ruleFiredCount + "条规则");if (result.isPostCodeResult()){System.out.println("规则校验通过");}kieSession.dispose();}@ResponseBody@RequestMapping("/reload")public String reload() throws IOException{reloadDroolsRules.reload();return "OK";}
}

drools7规则引擎相关推荐

  1. Drools 规则引擎死循环问题解决

    在<Drools7 规则引擎视频教程>中已经讲到,使用modify或update的时候在某种程度上会导致死循环. 昨天一同学在使用Drools规则引擎时便遇到了该问题.下面看该同学贴出来的 ...

  2. Drools规则引擎平台如何进行架构

    在<Drools7 规则引擎视频教程>的交流群中,有同学提出这样的问题:如果不想使用Drools官方提供的Workbench和KIE-Server进行规则的管理,而自行进行相应系统研发,该 ...

  3. 《Drools 规则引擎视频教程》相关事宜

    非常感谢大家能够有时间来看这篇博客,本篇博客主要介绍一下最近本人正在致力于的Drools 7 规则引擎文档和视频教程相关事项. Drools 本身在国内的技术网站上的资料就比较少,最近的视频教程更是几 ...

  4. java drools5_《Drools7.0.0.Final规则引擎教程》Drools5的使用详解

    2.1 Drools5简述 上面已经提到Drools是通过规则编译.规则收集和规则的执行来实现具体功能的.Drools5提供了以下主要实现API:KnowledgeBuilder KnowledgeB ...

  5. 《Drools7.0.0.Final规则引擎教程》第1章 Drools简介

    1.1 什么是规则引擎 规则引擎是由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策.接受数据输入,解释业务规则,并根据业务 ...

  6. 《Drools7.0.0.Final规则引擎教程》第4章 global全局变量

    global 全局变量 global用来定义全局变量,它可以让应用程序的对象在规则文件中能够被访问.通常,可以用来为规则文件提供数据或服务.特别是用来操作规则执行结果的处理和从规则返回数据,比如执行结 ...

  7. 规则引擎的介绍与Drools的流程分析

    规则引擎(RuleEngine)是一个有限状态机,通过入参实现状态转移,在Java中定义为JSR94规范.规则引擎目前的开源实现主要是JBoss家族的Drools,采用友好的Apache协议(意味着可 ...

  8. 反洗钱检验java_从Drools规则引擎到风控反洗钱系统V0.2.3.pdf

    本文档持续更新中,QQ 技术交流群:593177274,作者邮箱:secbro2@ 从Drools 规则引擎到风控反洗钱 -- <Drools7.0.0.Final 规则引擎教程> 修订日 ...

  9. mysql 规则引擎_Drools规则引擎详解-常用的drl实例

    package droolsDemo //说明:每个 drl 都必须声明一个包名,这个包名与 Java 里面的不同,它不需要与文件夹的层次结构一致, //主要用于可以根据kmodule.xml中不同的 ...

最新文章

  1. Java程序员从笨鸟到菜鸟之(九十)跟我学jquery(六)jquery中事件详解
  2. fzu - 1752 Problem 1752 A^B mod C
  3. 信捷plc485通信上位机_基于Snap7实现与西门子PLC通信
  4. #再一次用construct2做游戏
  5. 苹果雪豹操作系统正式版_Android 11 正式版发布!
  6. 超乎想象,数据揭示自学成才的码农为何备受青睐
  7. 性能优化实战案例——助力某移动OA系统
  8. 性能测试:性能测试常见指标
  9. tp中自定义跳转页面
  10. ISNULL与CASE函数
  11. 微信js-sdk集成小结
  12. jfreeChart生成报表
  13. Centos自动登录
  14. 【美港探案】百度Q2:需要重新定义
  15. 解决AndroidStudio编译工程长时间卡在Gradle:Build model问题
  16. VS中调试QT项目报错合集
  17. hnustoj 2108 湖南科技大学2019年大学生计算机程序设计新生赛
  18. Java最全的设计模式之行为设计模式前六种
  19. 计算机毕设(附源码)JAVA-SSM酒店客户管理系统
  20. 12c oracle 修改内存_Oracle12c中性能优化amp;功能增强新特性之重大突破——内存列存储新特性...

热门文章

  1. 本周末训练营免费直播:ESMO文章解构,扩展
  2. fatal - Error: Register plugin D:/youqu/yuntu-back/node_modules/@umijs/plugins/dist/layout.js failed
  3. R语言 类别数据可视化(2)
  4. 黑苹果EFI引导启动文件,惠普HP Z420+E5-1650v2(6)
  5. linux服务器 openshift,Openshift 指南
  6. Unity Mecanim动画系统 之 动画混合树(Blend Trees)的简单使用
  7. Evm7种重要指令的实现原理
  8. 炉石传说(NUPT-1969)
  9. 嵌入式操作系统复习——详细
  10. Conan教程(2)—— 安装