一、背景

在我们编写drl规则的时候,有些时候需要自己声明一些类,用于辅助之后的规则运行,如果需要用到的类还需要在java中预先声明出来,这样就不灵活了,那么是否可以在drl文件中声明一个类呢?可以使用drools的 Type declaration来实现。

二、前置知识

1、Type declaration语法结构

2、java代码中获取drl声明的类型

1、非枚举类型

KieBase kieBase = kieContainer.getKieBase("type-kabse");
// 规则文件的包名 声明的类型名
FactType productOrderFactType = kieBase.getFactType("rules", "ProductOrder");
Object instance = productOrderFactType.newInstance();
productOrderFactType.set(instance, "orderId", 20220517121212001L);

2、获取枚举类型的值

需要通过反射来获取到。

KieBase kieBase = kieContainer.getKieBase("type-kabse");
// 此处的FactType的真实类型是EnumClassDefinition,可以获取到枚举中构造方法的参数的值
FactType orderStatusFactType = kieBase.getFactType("rules", "OrderStatus"); // 获取drools中枚举的值
Class<?> factClass = orderStatusFactType.getFactClass();
Method method = factClass.getMethod("valueOf", String.class);
Object pay = method.invoke(null, "PAY");

注意:

如果上方的代码看不懂,则接着往下看。

三、需求

1、在drl文件中声明一个枚举类型。

2、在drl文件中声明一个类。

3、在drl文件中声明一个类并完成继承操作。

4、编写rule并使用我们自定义的type。

5、java中给在drl文件中声明的type赋值,包括类和枚举类型。

四、实现

1、在drl文件中声明一个枚举类型

// 声明一个枚举类型
declare enum OrderStatus
CREATED(0, "新创建"),
PAY(1, "已支付"),
RECEIVED(2, "已接收"); status: Integer;
desc: String;
end

语法结构: declare enum 枚举名字 end

2、在drl文件中声明一个类

// 声明一个类
declare BaseOrder
orderId: Long // 订单id
createdTime: Date // 时间
item: ProductItem // java中定义的类
orderStatus: OrderStatus // 上方定义的枚举类型
end

这个类中的每个属性都有一个类型,这个类型可以是已经存在的fact,也可以是任何有效的Java类型。

3、在drl文件中声明一个类并完成继承操作

// 实现继承操作
declare ProductOrder extends BaseOrder
userId: Long // 下单用户的id
end

使用extends来完成继承操作。

4、编写rule并使用我们自定义的type

// 定义一个规则,规则内存中存在ProductOrder并且 orderStatus是已支付userId==1001
rule "rule_type"
no-loop true
when
$order: ProductOrder(userId == 1001 && orderStatus == OrderStatus.PAY)
then
String createdTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format($order.getCreatedTime());
System.out.println("用户["+ $order.getUserId() +"]在["+ createdTime +"]购买的["+ $order.getItem().getItemName() +"]已完成付款");
modify($order){
setOrderStatus(OrderStatus.RECEIVED)
}
end

解释:

1、如果规则内存中存在ProductOrder对象,并且userId的值是1001orderStatus的值是PAY则该规则被激活了。

2、当该规则激活时,修改订单的状态为RECEIVED,在java代码中获取修改后的值。

5、java中给在drl文件中声明的type赋值

@Slf4j
public class DroolsTypeDeclareApplication { public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
KieServices kieServices = KieServices.get();
KieContainer kieContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieContainer.newKieSession("type-ksession");
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
kieSession.addEventListener(new DebugAgendaEventListener());
kieSession.addEventListener(new DebugProcessEventListener()); KieBase kieBase = kieContainer.getKieBase("type-kabse");
FactType productOrderFactType = kieBase.getFactType("rules", "ProductOrder");
FactType orderStatusFactType = kieBase.getFactType("rules", "OrderStatus"); // 获取drools中枚举的值
Class<?> factClass = orderStatusFactType.getFactClass();
Method method = factClass.getMethod("valueOf", String.class);
Object pay = method.invoke(null, "PAY"); Object instance = productOrderFactType.newInstance(); ProductItem item = new ProductItem();
item.setItemName("iphone 13"); productOrderFactType.set(instance, "orderId", 20220517121212001L);
productOrderFactType.set(instance, "createdTime", new Date());
productOrderFactType.set(instance, "item", item);
productOrderFactType.set(instance, "orderStatus", pay);
productOrderFactType.set(instance, "userId", 1001L); kieSession.insert(instance);
kieSession.fireAllRules(); Object orderStatus = productOrderFactType.get(instance, "orderStatus");
log.info("获取rule中修改之后的枚举字段的值:[{}]", orderStatus); kieSession.dispose();
}
}

注意:

1、在java中获取到drl文件中声明的类型,需要使用 kieBase.getFactType来获取。

2、如果需要获取到drl文件中申明的枚举类型的值,可以通过反射来获取。

6、运行上方的代码

用户[1001]在[2022-05-17 11:42:27]购买的[iphone 13]已完成付款
11:42:27.724 [main] INFO com.huan.drools.querys.DroolsTypeDeclareApplication - 获取rule中修改之后的枚举字段的值:[RECEIVED]

可以看到规则执行了,并且java中也获取到了工作内存中修改后的值。

五、完整代码

https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-type-declarations

六、参考链接

1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#drl-declarations-con_drl-rules

drools的类型声明(Type declarations)的更多相关文章

  1. Go语言规格说明书 之 类型声明(Type declarations)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,完整的介绍Go语 ...

  2. [Effective Modern C++] Item 5. Prefer auto to explicit type declarations - 相对显式类型声明,更倾向使用auto

    条款5 相对显式类型声明,更倾向使用auto 基础知识 auto能大大方便变量的定义,可以表示仅由编译器知道的类型. template<typename It> void dwim(It ...

  3. Return type declarations返回类型声明

    PHP 7.新增了返回类型声明 http://php.net/manual/en/functions.returning-values.php 在PHP 7.1中新增了返回类型声明为void,以及类型 ...

  4. Effective Modern C++翻译(6)-条款5:auto比显示的类型声明要更好

        在概念上说,auto关键字和它看起来一样简单,但是事实上,它要更微妙一些的.使用auto会让你在声明变量时省略掉类型,同时也会防止了手动类型声明带来的正确性和性能上的困扰:虽然按照语言预先定义 ...

  5. 如何阅读复杂的C类型声明

    阅读复杂的C类型声明,通常采用右左法则,也就是Clockwise/Spiral Rule (顺时针/螺旋法则). 本文将首先介绍工具(cdecl)(个人比较偏好使用工具提高学习和工作效率),然后中英文 ...

  6. Swift编程语言学习12 ——实例方法(Instance Methods)和类型方法(Type Methods)

    方法是与某些特定类型相关联的函数.类.结构体.枚举都能够定义实例方法:实例方法为给定类型的实例封装了详细的任务与功能.类.结构体.枚举也能够定义类型方法:类型方法与类型本身相关联.类型方法与 Obje ...

  7. 读书笔记 effective c++ Item 19 像设计类型(type)一样设计

    1. 你需要重视类的设计 c++同其他面向对象编程语言一样,定义了一个新的类就相当于定义了一个新的类型(type),因此作为一个c++开发人员,大量时间会被花费在扩张你的类型系统上面.这意味着你不仅仅 ...

  8. 父类通过泛型获得子类Class类型 以及Type体系

    1.背景介绍 在实现SSH框架中,DAO层向数据库持久化的过程中,因为大部分保存对象的方法都会调用到sava():所有索性就把save delete update select 方法进行封装到父类中, ...

  9. item 5: 比起显式的类型声明,更偏爱auto

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 啊,简单愉快的代码: int x; 等等,讨厌!我忘了初始化x,所 ...

随机推荐

  1. Python turtle 模块可以编写游戏,是真的吗?

    1. 前言 turtle (小海龟) 是 Python 内置的一个绘图模块,其实它不仅可以用来绘图,还可以制作简单的小游戏,甚至可以当成简易的 GUI 模块,编写简单的 GUI 程序. 本文使用 tu ...

  2. PYthon窗口学习之用异步请求解决Treeview列表插入大量数据反应慢的解决办法

    当列表插入大量数据时,经常会等一会才显示数据 异步请求就将每一个插入语句并发运行,从而提高插入速度 代码: # 显示结果 def insert_result(table, info): def ins ...

  3. 【小程序开发】文本text-overflow属性的使用

    text-overflow原本是CSS3的一个属性,在微信小程序中也支持. text-overflow文本溢出显示省略号~ 注:使用text-overflow时,需要设置固定的宽度才起作用,所以该元素 ...

  4. 主线程中的Looper.loop()为什么不会造成ANR

    引子: 正如我们所知,在android中如果主线程中进行耗时操作会引发ANR(Application Not Responding)异常. 造成ANR的原因一般有两种: 当前的事件没有机会得到处理(即 ...

  5. Exchange日志清理

    1.清理日志--完整备份 Exchange Server 2013被部署在Windows Server 2012 及以上版本的操作系统中,使用操作系统内的"Windows Server Ba ...

  6. C# 一个基于.NET Core3.1的开源项目帮你彻底搞懂WPF框架Prism

    --概述 这个项目演示了如何在WPF中使用各种Prism功能的示例.如果您刚刚开始使用Prism,建议您从第一个示例开始,按顺序从列表中开始.每个示例都基于前一个示例的概念. 此项目平台框架:.NET ...

  7. Java报错:Injection of resource dependencies failed

    在学习springMVC+Mabatis的时候,添加注解@Resource报错 Injection of resource dependencies failed de完bug后发现有几个点注意一下, ...

  8. 小天才XTC Z1S开启ADB

    起因 最近入手了Apple Watch,但因系统闭源和国区App Store第三方应用实在是少,所以就开始折腾起安卓表来了.正好家里有块给小孩子用的小天才手表,所以就想到了通过ADB调试安装一些这块表 ...

  9. 基于docker搭建laravel项目

    基于docker搭建laravel项目 公司PHP项目是Laravel框架写的,目前环境需要通过docker来部署一下.网上学习了一下相关知识.整理后做一个笔记.用到定时任务crontab与进程管理s ...

  10. grpc流模式-go实现

    目录 1. 什么是数据流 2. grpc的四种数据流 2.1 简单模式 2.2 服务端数据流模式 2.3 客户端数据流模式 2.4 双向数据流 3. 上代码 3.1 代码目录 3.2 编写stream ...