一、背景
在我们编写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 // 下单用户的idend
使用extends
来完成继承操作。
4、编写rule并使用我们自定义的type
// 定义一个规则,规则内存中存在ProductOrder并且 orderStatus是已支付userId==1001rule "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的值是1001
,orderStatus的值是PAY
则该规则被激活了。 2、当该规则激活时,修改订单的状态为RECEIVED
,在java代码中获取修改后的值。
5、java中给在drl文件中声明的type赋值
@Slf4jpublic 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
原文:https://juejin.cn/post/7098585271502897183