首页
关于
Search
1
阿里云更换SSL证书
308 阅读
2
Nginx+Lua脚本控制负载均衡
176 阅读
3
地址相似度算法
166 阅读
4
【学习笔记】ES新特性
163 阅读
5
原生Hadoop搭建
140 阅读
默认分类
技术
JAVA
python
前端
大数据
运维
登录
Search
标签搜索
学习笔记
Javascript
前端
算法
负载均衡
Lua
Nginx
Kafka
Hive
Hbase
大数据
Hadoop
gitlab
CSS
HTML
ES语法
规则引擎
Drools
模型
springboot
枉自朝朝暮暮
累计撰写
12
篇文章
累计收到
1
条评论
首页
栏目
默认分类
技术
JAVA
python
前端
大数据
运维
页面
关于
搜索到
1
篇与
的结果
2021-09-10
Drools基础使用
Drools基础应用1. 为什么要使用规则擎if ("周一".equals(day)) { System.out.println("I will play basketball"); } else if ("周二".equals(day)) { System.out.println("I will do shopping"); } else if ("周三".equals(day)) { System.out.println("I will do shopping"); } else if ("周四".equals(day)) { System.out.println("I will do shopping"); } else if (...) { ... } else { ... }产品需求1:周二不应该do shopping,应该要play switch产品需求2:周五、周六、周日呢?实际生产情况可能涉及的规则更为复杂多变,如何修改上述代码呢。可能有人会使用策略模式、模板方法、装饰器、工厂方法之类,但那仅仅是针对于代码层面的优化。但针对于复杂的业务逻辑,还需要做到以下几点:简化if else结构,让业务逻辑和数据分离!分理处的业务逻辑必须要易于编写,至少单独编写这些业务逻辑,要比写代码快!分离出的业务逻辑必须要比原来的代码更容易读懂!分离出的业务逻辑必须比原来的易于维护,至少改动这些逻辑,应用程序不用重启!基于此种需求,规则引擎诞生了。规则引擎是一种嵌套在应用程序中的组件,它实现了将业务规则从应用程序代码中分离出来。规则引擎使用特定的语法编写业务规则,规则引擎可以接受数据输入、解释业务规则、并根据业务规则做出相应的决策。市面上的规则引擎框架有很多,Aviator、Drools、RasyRules、RuleBook、Ikexpression、MVEL、JRules、JLisa、QuickRules等等。但是更多的公司还是选择Drools作为生产应用的规则引擎。2.Drools简介Drools是由Java语言开发的开源业务规则引擎,其具有一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准、速度快、效率高。业务分析师或者审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。Drools具有以下优点:活跃的社区支持简洁易用快速的执行速度:Rete算法在Java开发人员中流行2.1 HelloWorld2.1.1引入Maven依赖 <!-- drools --> <dependency> <groupId>org.kie</groupId> <artifactId>kie-internal</artifactId> <version>7.10.0.Final</version> </dependency> <dependency> <groupId>org.kie</groupId> <artifactId>kie-api</artifactId> <version>7.10.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>7.10.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>7.10.0.Final</version> </dependency>2.1.2创建一个JavaBeanpublic class DailyProgram { int day; String plan = "无"; public int getDay() { return day; } public void setDay(int day) { this.day = day; } public String getPlan() { return plan; } public void setPlan(String plan) { this.plan = plan; } }2.1.3创建kmodule.xml,放在resources目录的META-INF文件夹下<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> <kbase name="daily_program" packages="rules"> <ksession name="daily_program_session" type="stateful"/> </kbase> </kmodule>2.1.4创建规则文件dailyprogram.drlpackage wang.myrule; import wang.smalleyes.drools.bean.DailyProgram; function String hello(String name){ return "Hello " + name + "!"; } rule "day1" when $dailyProgram: DailyProgram(day == 1); then $dailyProgram.setPlan("I will play basketball"); System.out.println( "exec rule day1 ... " ); System.out.println( hello("day1") ); end 2.1.5测试规则运行public void testRules1(){ //创建KieServices KieServices kieServices = KieServices.get(); //创建KieServices,classPathContainer默认获取META-INF下的kmodule.xml KieContainer kieContainer = kieServices.getKieClasspathContainer(); //按名称指定获取KieSession KieSession kieSession = kieContainer.newKieSession("daily_program_session"); DailyProgram dailyProgram = new DailyProgram(); dailyProgram.setDay(1); kieSession.insert(dailyProgram); int fireCount = kieSession.fireAllRules(); kieSession.dispose(); System.err.println(dailyProgram.getPlan()); System.out.println("规则执行击中" + fireCount + "条规则"); }运行结果如下:2.2重要的APIKieServices:KIE整体的入口,可以用来创建下面这些API等。KieContainer:KieBase的容器,根据kmodule.xml里描述的信息获取具体的KieSession、KieBase;KieBase:就是一个知识仓库,包含了若干的规则、流程、方法等,在Drools中主要就是规则和方法,KieBase本身并不包含运行时的数据之类的,如果需要执行规则KieBase中的规则的话,就需要根据KieBase创建KieSessionKieSession:KieSession就是一个跟Drools引擎打交道的会话,其基于KieBase创建,它会包含运行时数据,包含“事实 Fact”,并对运行时数据事实进行规则运算KieModule:是一个包含了多个kiebase定义的容器。一般用kmodule.xml来表示2.3KieSessionKieSession在创建时可指定创建为有状态Session或无状态Session。有状态Session:它可以在交互的同时,保持住状态。这就是有状态的会话。当我们不想再使用KieSession的时候,那么我们必须显示的调用dispose()方法来声明下。有状态Session使用fireAllRules()方法执行规则。无状态Session:无状态的KieSession会将这种会话描述为一个函数,具有无状态以及原子性。理想情况下,函数不应该具有任何间接影响。无状态Session使用execute()方法执行规则。在Kmodule.xml文件中定义Kbase下的Kession,由属性type可以控制无状态(stateless)或者有状态(stateful)。或者通过以下API创建kieContainer.newStatelessKieSession(”daily_program_session“);有状态和无状态的区别在于多次会话时,有状态会保留前次计算的信息,而无状态多次运算之间是不相互影响的。2.4规则文件语法2.4.1 package在一个规则文件当中 package 是必须的,而且必须放置在文件的第一行。package 的名字是随意的,不必必须对应物理路径,这里跟 java 的package 的概念不同,只是逻辑上的区分,但建议与文件路径一致。同一的 package 下定义的 function 和 query 等可以直接使用。如:package wang.myrule;2.4.2 import导入规则文件需要的外部变量,使用方法跟 java 相同。 和 java 的 import 一样, 还可以导入类中的某一个可访问的静态方法。import wang.smalleyes.drools.bean.DailyProgram;2.4.3 globalglobal用于定义全局变量。它可以让应用程序的对象在规则文件中能够被访问。通常,可以用来为规则文件提供数据或服务。在规则执行前由kieSession注入。@Autowired private EmailService emailService ... kieSession.setGlobal("emailService", emailService); drl文件中的用法:import wang.smalleyes.drools.EmailService; global EmailService $emailService; rule "rule1" when ... then $emailService.sendEmail() end2.4.4 方法定义——function将语义代码放置在规则文件中的一种方式,就相当于java类中的方法package wang.myrule; import wang.smalleyes.drools.bean.DailyProgram; function String hello(String name){ return "Hello " + name + "!" } rule "rule1" when ... then hello("tom"); end2.4.5规则定义rule "rule1" //规则名称,全局唯一 attributes //规则属性 when LHS //规则执行条件 then RHS //规则执行结果 end常用的attributes规则属性:no-loop:定义当前的规则是否不允许多次循环执行,默认是 false,也就是当前的规则只要满足条件,可以无限次执行。当执行Update、insert方法更新Fact对象时,会触发规则执行。salience:规则执行顺序,值越大,越优先执行3.Springboot整合问题在本地运行时,规则中的globals引用的外部服务,始终无法被Drools找到,显示Null。经过Debug后,发现是引用了SpringBoot的dev-tools依赖,开启了热加载。原因:dev-tools开启后,被Spring管理的bean的类加载器使用了自定义的RestartClassLoader。而Drools在运行时,获取的类的类加载器是AppClassLoader。因为类加载器不一致,并不是由双亲委派模型的下的上级类加载器加载进来,对于一个类,由不同的类加载器实例加载的话,会在方法区产生两个不同的类,彼此不可见,并且在堆中生成不同Class实例(所有通过正常双亲委派模式的类加载器加载的classpath下的和ext下的所有类在方法区都是同一个类,堆中的Class实例也是同一个)。因为两者不一致,所以drools在workingmemory中使用的是AppAppClassLoader的实例自然无法找到由RestartClassLoader加载的实例。解决方式:将Drools升级至7.23.0FINAL或更高版本。取出SpringBoot的dev-tools依赖。4.Drools热部署——实时更新KieBase@Test public void testRules(){ KieServices kieServices = KieServices.get() KieContainer kieContainer = kieServices.getKieclasspathContainer() KieSession kieSession = kiecontainer.newKieSession("daily_program_ session") KnowledgeBaseImpl kieBase(KnowledgeBaseImpl)kieContainer.getKieBase("daily_program"); //实时更新规则 insertRules(kieBase) DailyProgram dailyProgram = new DailyProgram(); dailyProgram.setDay(1); kieSession.insert(dailyProgram) DailyProgram dailyProgram2 = new DailyProgram(); dailyProgram2.setDay(2); kieSession.insert(dailyProgram2) int firecount = kiesession,fireAllRules() kieSession.dispose() System.err.println(dailyProgram.getPlan()); System.err.println(dailyProgram2.getPlan()); System.out.println("规则执行击中”+firecount +"条规则") } private void insertRules(KnowledgeBaseImpl kieBase){ String rule = "package com.myrule;\n" + "\n" + "import wang.smalleyes.drools.bean.DailyProgram;\n" + "\n" + "rule \"day2\"\n" + "\n" + "when\n" + "$dailyProgram: DailyProgram(day == 2);\n" + "then\n" + "$dailyProgram.setPlan(\"I will do shopping\");\n" + "System.err.println(\"exec rule day2 ...\");\n" + "end\n"; KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(kieBase); kbuilder .add(ResourceFactory.newByteArrayResource(rule.getBytes()) .setSourcePath("com/myrule/new.drl") ,ResourceType.DRL). if(kbuilder.hasErrors()){ System.err.println("规则加载异常"); } Collection<KiePackage> kiePackages = kbuilder.getKnowledgePackages(); kieBase.addPackages(kiePackages); }KnowledgeBuilder:在业务代码中收集已编写的规则,并对规则文件进行编译,生成编译好的KnowledgePackage集合,提供给其他API使用。KiePackage:编译好的规则包执行结果:
2021年09月10日
114 阅读
0 评论
0 点赞