drools规则引擎笔记
文章目录
一、使用示例
1.规则过滤器
通过
AgendaFilter
限制fire,默认支持equals、startWith、endWith、Pattern,可自定义AgendaFilter
。
final int count = kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule1"));
2.session连接池
- kContainer
KieContainerSessionsPool pool = kContainer.newKieSessionsPool(10);
KieSession kSession = pool.newKieSession();
- kieBase
final KieSessionsPool kieSessionsPool = kieBase.newKieSessionsPool(10);
KieSession kSession = kieSessionsPool.newKieSession();
3.debug log
ksession.addEventListener( new DebugRuleRuntimeEventListener() );
- pom.xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
- logback.xml
<configuration>
<logger name="org.drools" level="debug"/>
...
<configuration>
Drools engine event listeners and debug logging
4.规则内容与模型互转
@Test
public void testPackageDescr() {
// 默认生成drl
final PackageDescr descr = DescrFactory.newPackage().name("com.example.demo")
.newImport().target(java.util.List.class.getName()).end()
.newGlobal().type(java.util.List.class.getName()).identifier("count").end()
.newRule().name("rule1")
.attribute("enabled","true")
.lhs()
.pattern(Person.class.getName()).id("$p", false).constraint("name==\"张三\"").end()
.end()
.rhs("System.out.println($p);")
.end()
.end()
.getDescr();
final String drl = new DrlDumper().dump(descr);
System.out.println(drl);
System.out.println("=================================================================");
// drl解析成模型
DrlParser drlParser = new DrlParser();
final StringReader reader = new StringReader(drl);
try {
// 语法结构解析,不做环境校验(例如Person类是否存在)
final PackageDescr descr1 = drlParser.parse(reader);
if (drlParser.hasErrors()) {
System.out.println(drlParser.getErrors());
throw new DroolsParserException("The model drl " + drl + " is not valid");
} else {
final String drl1 = new DrlDumper().dump(descr1);
System.out.println(drl1);
}
} catch (DroolsParserException e) {
e.printStackTrace();
}
}
二、规则编译及动态加载
1.校验jar包中的规则
- KieContainer方式
KieServices ks = KieServices.Factory.get();
ReleaseId releaseId = ks.newReleaseId("com.example", "demo", "1.0");
final KieContainer kieContainer = ks.newKieContainer(releaseId);
final Results results = kieContainer.verify();
final List<Message> messages = results.getMessages(Message.Level.ERROR);
- KieHelper方式
KieHelper kieHelper = new KieHelper();
kieHelper.addContent(content, ResourceType.DRL);
Results results = kieHelper.verify();
if (results.hasMessages(Message.Level.WARNING, Message.Level.ERROR)) {
List<Message> messages = results.getMessages(Message.Level.WARNING, Message.Level.ERROR);
System.out.println(messages);
}
2.自定义classloader
- KieBuilder 方式
KieServices ks = KieServices.Factory.get();
final KieBuilder kieBuilder = ks.newKieBuilder(kfs, classLoader)
- KieHelper方式
KieHelper kieHelper = new KieHelper();
kieHelper.setClassLoader(classLoader);
3.动态生成kjar并编译规则
@Test
public void buildRulesTest() {
KieServices ks = KieServices.Factory.get();
ReleaseId releaseId = ks.newReleaseId("com.example", "demo", "1.0");
// kieModule模型
KieModuleModel kieModuleModel = ks.newKieModuleModel();
kieModuleModel.newKieBaseModel()
.addPackage("com.example.demo")
.setDefault(true)
.newKieSessionModel("session")
.setType(KieSessionModel.KieSessionType.STATEFUL);
// 内存文件系统
KieFileSystem kfs = ks.newKieFileSystem()
.generateAndWritePomXML(releaseId)
.write("src/main/resources/com/example/demo/r1.drl", "package com.example.demo;\n" +
"\n" +
"import com.example.drools.Person \n" +
"dialect \"mvel\"\n" +
"\n" +
"\n" +
"\n" +
"global java.lang.Integer count1;\n" +
"\n" +
"rule \"rule1\"\n" +
" when\n" +
" $p:Person(name == \"张三\")" +
" then\n" +
" System.out.println(\"rule1\");\n" +
"end\n")
.writeKModuleXML(kieModuleModel.toXML());
/**
* 编译并自动添加到repository仓库
* @see org.drools.compiler.kie.builder.impl.KieBuilderImpl#buildKieProject(org.drools.compiler.kie.builder.impl.ResultsImpl, org.drools.compiler.kie.builder.impl.KieModuleKieProject, org.drools.compiler.compiler.io.memory.MemoryFileSystem)
*/
final KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
final Results results = kieBuilder.getResults();
final boolean b = results.hasMessages(Message.Level.ERROR);
if (b) {
System.out.println(results.getMessages());
throw new RuntimeException(results.toString());
} else {
final KieContainer kieContainer = ks.newKieContainer(releaseId);
KieSession ksession = kieContainer.newKieSession("session");
final Person person = new Person();
person.setName("张三");
person.setAge(21);
ksession.insert(person);
int count = ksession.fireAllRules();
ksession.dispose();
System.out.println(count);
}
}
4.动态加载自定义类和规则文件
- 常量
private static final String FILE_SEPARATOR = "/";
private static final String SOURCE_PATH = "src/main/java";
private static final String RESOURCE_PATH = "src/main/resources";
- 动态加载自定义类
final KieHelper kieHelper = new KieHelper();
// 全限类名
String fullQualifiedName = "com.example.Test";
// java源代码
String code = "...";
final Resource resource = ResourceFactory.newByteArrayResource(code.getBytes(StandardCharsets.UTF_8));
resource.setSourcePath(SOURCE_PATH + FILE_SEPARATOR + fullQualifiedName.replace(".", FILE_SEPARATOR) + ".java");
// 解决规则文件函数(本质是通过JavaCompiler编译java源代码生成class字节码)的源码编译依赖问题
kieHelper.addResource(resource, ResourceType.JAVA);
- 动态加载规则文件
String drl = "...";
kieHelper.addContent(drl, ResourceType.DRL);
- 动态赋值及规则调用
// 注意:不要执行 kieHelper.build(),此为无用功,且此处的kieBase和kieContainer.getKieBase()虽然均为defaultKieBase,但由于不是同一个kieContainer,所以它们也不是统一kieBase
// final KieBase kieBase = kieHelper.build();
final KieContainer kieContainer = kieHelper.getKieContainer();
final ClassLoader classLoader = kieContainer.getClassLoader();
final Class<?> aClass = classLoader.loadClass("com.example.TestInfo11");
// 反射操作
final Object obj = aClass.newInstance();
/**
* 注意:每次调用kieHelper.getKieContainer()都会重新编译规则和类;kieHelper.build()本质也是调用kieHelper.getKieContainer()
* ,所以classloader会不断变化,动态编译类的class对象也不相同。
*/
final KieSession kieSession = kieContainer.newKieSession();
kieSession.insert(obj);
final int count = kieSession.fireAllRules();
System.out.println(count);
kieSession.dispose();