Drools入门之规则流
普通运行方式
-
引入依赖
<dependency> <groupId>org.jbpm</groupId> <artifactId>jbpm-test</artifactId> <version>${drools.version}</version> <!-- 我使用的是7.10.0.Final --> </dependency>
-
在rules/isFlow下新建ruleFlow.bpmn文件。
-
打开properites窗口,修改规则流属性。
修改id为:No1_drools;package为:rules.isFlow
ID在当前规则库中的逻辑路径是唯一的,这点与规则文件rule name是一样的,package指规则流程文件的逻辑路径,与规则文件中的package功能一样。
-
创建规则文件ruleFlow.drl,目录为rules/isFlow
package rules.isFlow rule "rule folw example1" dialect "mvel" ruleflow-group "No1_drools_RuleFlow" when eval(true) then System.out.println("输出第一个规则流") end rule "rule no folw example1" dialect "mvel" when eval(true) then System.out.println("没有使用规则流") end
-
配置任务元素组件,通过元素组件画出如下图所示的效果,并选中规则任务元素组件,设置“RuleFlowGroup:No1_drools_RuleFlow”选项,该值要与规则文件中的ruleflow-group保持一致。
-
修改kmodule.xml配置文件
<kbase name="flow" packages="rules.isFlow"> <ksession name="testFlow"/> </kbase>
-
创建测试方法
@Test public void testFlow() { KieServices kieService = KieServices.Factory.get(); KieContainer kieContainer = kieService.getKieClasspathContainer(); KieSession kieSession = kieContainer.newKieSession("testFlow"); kieSession.startProcess("No1_drools"); //启动流程 kieSession.fireAllRules(); kieSession.dispose(); }
-
执行结果
输出第一个规则流 没有使用规则流
若没有加
kieSession.startProcess("No1_drools");
这行代码,就不会执行第一个规则。
API调用方式
@Test
public void testIsFlowAPI() {
Resource bpmn = ResourceFactory.newClassPathResource("rules/isFlow/ruleFlow.bpmn",this.getClass());
Resource drl = ResourceFactory.newClassPathResource("rules/isFlow/ruleFlow.drl",this.getClass());
KieHelper helper = new KieHelper();
helper.addResource(bpmn,ResourceType.BPMN2);
helper.addResource(drl,ResourceType.DRL);
KieSession kieSession = helper.build().newKieSession();
kieSession.startProcess("No1_drools"); //启动流程
kieSession.fireAllRules();
kieSession.dispose();
}
总结
- 当流程文件元素组件只有一个,多个规则体属性ruleflow-group相同,且流程文件元素组件的RuleFlowGroup属性与规则体的属性相同时,则会执行满足条件的规则。
- 当流程文件有多个规则元素组件,该规则元素组件的RuleFlowGroup相同,多个规则体属性ruleflow-group相同,且流程文件元素组件的RuleFlowGroup属性与规则体的属性相同时,则会执行满足条件的规则,并且只会执行一遍,不会因规则元素组件的增多而执行多次规则。但凡是规则流参数相同的规则体都会受salience的影响,这点需要格外注意。
- 当流程文件有多个规则元素组件,并且该规则元素组件的RuleFlowGroup是不相同的,多个规则体属性ruleflow-group与规则元素组件一一对应时,则会执行满足条件的规则。就算在规则体中设置了salience属性,规则元素组件也不会受其影响而改变规则的执行顺序。
- 流程文件中规则元素组件的RuleFlowGroup值与规则文件中规则体属性ruleflow-group没有匹配时,则规则不会被执行。
综上所述,使用规则流属性时必须添加流程文件,规则体中规则流属性要与流程文件规则元素组件的RuleFlowGroup一一对应。规则流的执行会受其他属性的影响,并且还会受流程文件元素组件顺序的影响。
规则流中的Java代码
静态方法调用
-
创建FlowToJava.java文件
package com.rulesHello; public class FlowToJava { public static void flowToJava1() { System.out.println("输出第一个通过流程调用java方法"); } }
-
创建规则文件flowToJava.drl,目录为rules/isFlow/flowJava
package rules.isFlow.flowJava rule "规则流调用java例子1" ruleflow-group "flowToJava" when then System.out.println(drools.getRule().getName()); end
-
创建流程文件flowToJava.bpmn
-
设置规则流属性
规则流id:flowToJava,package:rules.isFlow.flowJava
Rule TaskK组件RuleFlowGroup:flowToJava
-
设置Script元素组件,设置如下图所示
-
配置kmodule.xml
<kbase name="flowToJava" packages="rules.isFlow.flowJava"> <ksession name="testFlowToJava"/> </kbase>
-
测试方法
@Test public void testFlowToJava() { KieServices kieService = KieServices.Factory.get(); KieContainer kieContainer = kieService.getKieClasspathContainer(); KieSession kieSession = kieContainer.newKieSession("testFlowToJava"); kieSession.startProcess("flowToJava"); //启动流程 kieSession.fireAllRules(); kieSession.dispose(); }
-
运行结果
输出第一个通过流程调用java方法 规则流调用java例子1
非静态方法调用
-
创建FlowToJavaTwo.java文件,目录为comTwo/flow,其内容为:
public class FlowToJavaTwo { private static final FlowToJavaTwo FLOW = new FlowToJavaTwo(); public static FlowToJavaTwo getFlow() { return FLOW; } public void flowToJava02() { System.out.println("第二种通过单例模式调用Java方法"); } }
-
修改规则流
-
修改非静态的action信息
-
运行测试方法
-
输出日志
输出第一个通过流程调用java方法 第二种通过单例模式调用Java方法 规则流调用java例子1
传参
若要调用有参数的方法,如何传参呢?
-
首先创建一个带有参数的方法
public class FlowToJava { public static void flowToJava02(String value) { System.out.println("输出传递的参数:"+value); } }
-
修改规则流中调用的方法
-
点击规则流文件的空白部分,修改Variables属性(Name要和上面的参数名一致)
-
修改测试方法(map的key要和上面设置的一致)
@Test public void testFlowToJava() { KieServices kieService = KieServices.Factory.get(); KieContainer kieContainer = kieService.getKieClasspathContainer(); KieSession kieSession = kieContainer.newKieSession("testFlowToJava"); Map<String,Object> map = new HashMap<String, Object>(); map.put("value", "我是传递的参数"); kieSession.startProcess("flowToJava",map); //启动流程 kieSession.fireAllRules(); kieSession.dispose(); }
-
运行测试方法,输出结果
输出传递的参数:我是传递的参数 第二种通过单例模式调用Java方法 规则流调用java例子1
规则流中的网关
网关可以分为两种:分离网关和合并网关。为了适应官方文档上的方式,先将bpmn的展现方式做一个变化。
网关分为分离网关和合并网关两种,这两种网关都可以设置不同的type,它们都有AND和XOR,但分离网关多一种OR。
介绍完这两种网关的基本知识,下面对其类型分别进行测试。创建separation.bpmn文件。
其中Action组件设置为System.out.println()
输出。输出的内容为显示为Action组件的名称。
分离网关与合并网关type都为AND
分离网关的的type设置为AND,合并网关的type设置为AND。
创建测试方法
@Test
public void testFlowGeteway() {
Resource bpmn = ResourceFactory.newClassPathResource("rules/isFlow/gateway/separation.bpmn",this.getClass());
KieHelper helper = new KieHelper();
helper.addResource(bpmn,ResourceType.BPMN2);
KieSession kieSession = helper.build().newKieSession();
kieSession.startProcess("gateway"); //启动流程
kieSession.fireAllRules();
kieSession.dispose();
}
执行方法,输出结果为
start
分支三为True
分支二为False
分支一为True
end
当所有网关都为AND时,流程元素组件都将会被访问。
合并网关type为XOR
将合并网关type改为XOR。执行结果
start
分支三为True
end
当分离网关为AND,合并网关为XOR时,只会执行其中一个流向,这点与规则属性activation-group很相似。
分离网关的type为XOR
将分离网关的type设置成XOR,多了一个Constraints可选参数,单击该参数进行配置
从上图中可以看到,将分离网关设置在XOR后,是可以在每一条连接线进行设置,并且设置该连接线又会分为以下几种情况。
- name:表示连接线的名称。
- priority:表示连接线的优先级,值越小优先级越高。
- Always true:表示永远为true。
- Type:表示以什么方式进行判断结果,这里使用rule类型。
- Textual Editor:表示输入代码表达式的区域。
- Imports:表示可以引用其他类或方法。
- Globals:表示可以设置规则全局变量。
介绍完其作用后,分别对这3个分支进行设置:
分支一 name:f1,priority:1,规则:eval(true)
分支二 name:f2,priority:2,规则:eval(false)
分支三 name:f3,priority:3,规则:eval(true)
合并网关为AND
将合并网关设置为AND,执行测试方法,执行结果为:
start
分支一为True
总结:当分离网关为XOR,合并网关为AND时,无论分离网关是全True,还是有一个为True时,都不会执行到元素组件End。
合并网关为XOR
将合并网关的type设置成XOR
start
分支一为True
end
总结:当分离网关为XOR,合并网关为XOR时,分支中有两个为True,一个为False的情况下,只会有一个被执行,这是受优先级设置的影响。这证明只有分支为True的才会被执行并有且只有其中一个流向被执行。如果设置分支都为False,则会报如下图所示的错误。
分离网关为OR
合并网关为AND
执行结果
start
分支一为True
分支三为True
将所有的分支都设置为eavl(True),执行结果
start
分支一为True
分支二为False
分支三为True
end
总结:当分离网关为OR,合并网关为AND时,只有全部为True的情况下,所有流向才会被汇总,这也符合AND的逻辑与功能,如果分离网关所有分支为False时,则会报错。
合并网关为XOR
start
分支一为True
end
将分支1和2都设置为eavl(False)
start
分支三为True
end
总结:当分离网关为OR,合并网关为XOR时,只会执行分支为True的流向,并且只会汇总其中一个,这是受优先级影响。