Drools高级语法(6/6)
1、global全局变量
global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问。可以用来为规则文件提供数据或服务。
语法结构为:global 对象类型 对象名称
在使用global定义的全局变量时有两点需要注意:
1、如果对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。
第一步:编写global.drl
package testglobal /* 此规则文件用于测试global全局变量 */ global java.lang.Integer count //定义一个包装类型的全局变量 rule "rule_global_1" when then count += 10;//对于包装类型的全局变量的修改只针对当前规则生效 System.out.println("规则:rule_global_1触发了、、、"); System.out.println("全局变量count计算之后的值为: " + count); end rule "rule_global_2" when then System.out.println("规则:rule_global_2触发了、、、"); System.out.println("全局变量count计算之后的值为: " + count); end
第二步:编写测试类
@Test public void test5() throws InterruptedException { //设置日期格式 System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm"); KieServices kieServices = KieServices.Factory.get(); KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer(); final KieSession session = kieClasspathContainer.newKieSession(); //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应 session.setGlobal("count", 5); //激活 session.fireAllRules(); //关闭会话 session.dispose(); }
2、如果对象类型为集合类型或JavaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。
集合类型:
package testglobal /* 此规则文件用于测试global全局变量 */ global java.lang.Integer count //定义一个包装类型的全局变量 global java.util.List gList //定义一个集合类型的全局变量 rule "rule_global_1" when then count += 10;//对于包装类型的全局变量的修改只针对当前规则生效 System.out.println("规则:rule_global_1触发了、、、"); System.out.println("全局变量count计算之后的值为: " + count); gList.add("itcast"); //修改集合类型的全局变量 System.out.println("全局变量gList的size:" + gList.size()); end rule "rule_global_2" when then System.out.println("规则:rule_global_2触发了、、、"); System.out.println("全局变量count计算之后的值为: " + count); System.out.println("全局变量gList的size:" + gList.size()); end
@Test public void test5() throws InterruptedException { //设置日期格式 System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm"); KieServices kieServices = KieServices.Factory.get(); KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer(); final KieSession session = kieClasspathContainer.newKieSession(); //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应 session.setGlobal("count", 5); List<String> list = new ArrayList<String>(); list.add("itheima"); session.setGlobal("gList", list); //激活 session.fireAllRules(); System.out.println("在Java程序中全局变量glist的size为:" + list.size()); //关闭会话 session.dispose(); }
自定义对象类型
package testglobal import com.itheima.drools.service.UserService /* 此规则文件用于测试global全局变量 */ global java.lang.Integer count //定义一个包装类型的全局变量 global java.util.List gList //定义一个集合类型的全局变量 global UserService userService //定义一个JavaBean类型的全局变量 rule "rule_global_1" when then count += 10;//对于包装类型的全局变量的修改只针对当前规则生效 System.out.println("规则:rule_global_1触发了、、、"); System.out.println("全局变量count计算之后的值为: " + count); gList.add("itcast"); //修改集合类型的全局变量 System.out.println("全局变量gList的size:" + gList.size()); userService.save(); end rule "rule_global_2" when then System.out.println("规则:rule_global_2触发了、、、"); System.out.println("全局变量count计算之后的值为: " + count); System.out.println("全局变量gList的size:" + gList.size()); userService.save(); end
@Test public void test5() throws InterruptedException { //设置日期格式 System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm"); KieServices kieServices = KieServices.Factory.get(); KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer(); final KieSession session = kieClasspathContainer.newKieSession(); //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应 session.setGlobal("count", 5); List<String> list = new ArrayList<String>(); list.add("itheima"); session.setGlobal("gList", list); session.setGlobal("userService", new UserService()); //激活 session.fireAllRules(new RuleNameStartsWithAgendaFilter("rule_global")); System.out.println("在Java程序中全局变量glist的size为:" + list.size()); //关闭会话 session.dispose(); }
2、query查询
query查询提供了一种查询working memory中符合约束条件的Fact对象的简单方法。它仅包含规则文件中的LHS部分,不用指定“when”和“then”部分并且以end结束。具体语法结构如下:
query 查询的名称(可选参数)
LHS
end
具体操作步骤:
第一步:编写规则文件/resources/rules/query.drl
package testquery import com.itheima.drools.entity.Student /* 此规则文件用于测试query查询 */ //不带参数的查询 //当前query用于查询Working Memory中age>10的Student对象 query "query_1" $student:Student(age > 10) end query "query_2"(String sname) $student:Student(age > 5 && name == sname) end
第二步:编写单元测试
@Test public void test6() { //设置日期格式 System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm"); KieServices kieServices = KieServices.Factory.get(); KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer(); final KieSession session = kieClasspathContainer.newKieSession(); Student student1 = new Student(); student1.setAge(50); student1.setName("张三"); session.insert(student1); Student student2 = new Student(); student2.setAge(50); student2.setName("李四"); session.insert(student2); //根据名称调用规则文件中定义的查询 QueryResults result1 = session.getQueryResults("query_1"); int size = result1.size(); System.out.println("符合条件的Fact对象个数" + size); for (QueryResultsRow row : result1) { Student s = (Student)row.get("$student"); System.out.println(s); } QueryResults result2 = session.getQueryResults("query_2", "张三"); int size2 = result2.size(); System.out.println("符合条件的Fact对象个数" + size2); for (QueryResultsRow row : result2) { Student s = (Student)row.get("$student"); System.out.println(s); } // session.fireAllRules(); //关闭会话 session.dispose(); }
3、function函数
function关键字用于在规则文件中定义函数,就相当于java类中的方法一样。可以在规则体中调用定义的函数。使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改。
函数定义的语法结构如下:
function 返回值类型 函数名(可选参数){ //逻辑代码 }
具体操作步骤:
第一步:编写规则文件/resources/rules/function.drl
package testfunction import com.itheima.drools.entity.Student /* 此规则文件用于测试function函数 */ //定义一个函数 function String sayHello(String name) { return "hello " + name; } rule "rule_function_1" when $student:Student(name != null) then //调用上面定义的函数 String ret = sayHello($student.getName()); System.out.println(ret); end
第二步:编写单元测试
KieServices kieServices = KieServices.Factory.get(); KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer(); KieSession kieSession = kieClasspathContainer.newKieSession(); Student student = new Student(); student.setName("小明"); student.setAge(61); kieSession.insert(student); kieSession.fireAllRules(); kieSession.dispose();
4、LHS加强
在规则体中的LHS部分是介于when和then之间的部分,主要用于模式匹配,只有匹配结果为true时,才会触发RHS部分的执行。
4.1、复合值限制in/not in
复合值限制是指超过一种匹配值的限制条件,类似于SQL语句中的in关键字。Drools规则体中的LHS部分可以使用in或者not in进行复合值的匹配。具体语法结构如下:
Object(field in (比较值1,比较值2...))
举例:
$s:Student(name in ("张三","李四","王五"))
$s:Student(name not in ("张三","李四","王五"))
4.2、条件元素eval
eval用于规则体的LHS部分,并返回一个Boolean类型的值。语法结构如下:
eval(表达式)
举例:
eval(true) eval(false) eval(1 == 1)
4.3、条件元素not
not用于判断Working Memory中是否存在某个Fact对象,如果不存在则返回true,如果存在则返回false。语法结构如下:
not Object(可选属性约束)
举例:
not Student()
not Student(age < 10)
4.4、条件元素exists
exists的作用与not相反,用于判断Working Memory中是否存在某个Fact对象,如果存在则返回true,不存在则返回false。语法结构如下:
exists Object(可选属性约束)
举例:
exists Student() exists Student(age < 10 && name != null)
在LHS部分进行条件编写时并没有使用exists也可以达到判断Working Memory中是否存在某个符合条件的Fact元素的目的,那么我们使用exists还有什么意义?
两者的区别:当向Working Memory中加入多个满足条件的Fact对象时,使用了exists的规则执行一次,不使用exists的规则会执行多次。
例如:
规则文件(只有规则体):
rule "使用exists的规则" when exists Student() then System.out.println("规则:使用exists的规则触发"); end rule "没有使用exists的规则" when Student() then System.out.println("规则:没有使用exists的规则触发"); end
Java代码:
kieSession.insert(new Student()); kieSession.insert(new Student()); kieSession.fireAllRules();
上面第一个规则只会执行一次,因为Working Memory中存在两个满足条件的Fact对象,第二个规则会执行两次。
4.5、规则继承
规则之间可以使用extends关键字进行规则条件部分的继承,类似于java类之间的继承。
例如:
rule "rule_1" when Student(age > 10) then System.out.println("规则:rule_1触发"); end rule "rule_2" extends "rule_1" //继承上面的规则 when /* 此处的条件虽然只写了一个,但是从上面的规则继承了一个条件, 所以当前规则存在两个条件,即Student(age < 20)和Student(age > 10) */ Student(age < 20) then System.out.println("规则:rule_2触发"); end
需要注意的是,只继承条件
5、RHS加强
RHS部分是规则体的重要组成部分,当LHS部分的条件匹配成功后,对应的RHS部分就会触发执行。一般在RHS部分中需要进行业务处理。
在RHS部分Drools为我们提供了一个内置对象,名称就是drools。
5.1、halt
halt方法的作用是立即终止后面所有规则的执行。
package testhalt rule "rule_halt_1" when then System.out.println("规则:rule_halt_1触发"); drools.halt();//立即终止后面所有规则执行 end //当前规则并不会触发,因为上面的规则调用了halt方法导致后面所有规则都不会执行 rule "rule_halt_2" when then System.out.println("规则:rule_halt_2触发"); end
5.2、getWorkingMemory
getWorkingMemory方法的作用是返回工作内存对象。
package testgetWorkingMemory rule "rule_getWorkingMemory" when then System.out.println(drools.getWorkingMemory()); end
5.3、getRule
getRule方法的作用是返回规则对象。
package testgetRule rule "rule_getRule" when then System.out.println(drools.getRule()); end
6、规则文件编码规范
我们在进行drl类型的规则文件编写时尽量遵循如下规范:
- 所有的规则文件(.drl)应统一放在一个规定的文件夹中,如:/rules文件夹
- 书写的每个规则应尽量加上注释。注释要清晰明了,言简意赅
- 同一类型的对象尽量放在一个规则文件中,如所有Student类型的对象尽量放在一个规则文件中
- 规则结果部分(RHS)尽量不要有条件语句,如if(...),尽量不要有复杂的逻辑和深层次的嵌套语句
- 每个规则最好都加上salience属性,明确执行顺序
- Drools默认dialect为"Java",尽量避免使用dialect "mvel"
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY