Drools-核心概念入门
最近的开发涉及到了规则引擎Drools的一些开发,因为当中涉及到一些概念比如KieServices、KieContainer、KieModule、KieBase和KieSession他们各自是什么?各自起什么作用?当中有何种联系,基于这些疑问就对于其中的概念做了一个初步了解。
1. 首先需要解释的是什么是KIE?
KIE其实是 Knowledge is Everything 的简写
KIE是jBoss里面一些相关项目的统称,下图就是KIE代表的一些项目,其中我们比较熟悉的就有jBPM和Drools。
这些项目都有一定的关联关系,并且存在一些通用的API,比如说涉及到构建(building)、部署(deploying)和加载(loading)等方面的,这些API就都会以KIE作为前缀来表示这些是通用的API。前面看到的一些KieServices、KieContainer、KieSession类就都是KIE的公共API。 总的来说,就是jBoss通过KIE将jBPM和Drools等相关项目进行了一个整合,统一了他们的使用方式。像KieServices这些KIE类就是整合后的结果,在Drools中这样使用,在jBPM里面也是这样使用。

2. KieServices和KieContainer
KieServices是进行规则引擎操作的起始点。通过KieService可以获得Drools中的其他组件。
在Drools 6.x版本中,可以通过下面的方式来获取KieService KieServices ks = KieServices.Factory.get(); 在Drools7.x版本中,可以通过下面的方式获取KieService KieServices ks = KieServices.get();
通过KieServices可以获取到KieContainer。KieContainer确定了当创建规则引擎实例时所包含的规则范围。
通过KieServices对象得到一个KieContainer,利用kieContainer对象创建一个新的KieSession,
创建session的时候我们传入了一个name:“ksession-name”,这个字符串很眼熟吧,这个就是我们定义的kmodule.xml文件中定义的ksession的name。kieContainer根据kmodule.xml定义的ksession的名称找到KieSession的定义,然后创建一个KieSession的实例。
KieSession就是一个到规则引擎的链接,通过它就可以跟规则引擎通讯,并且发起执行规则的操作。通过kSession.insert方法来将事实(Fact)插入到引擎中,也就是Working Memory中。
然后通过kSession.fireAllRules方法来通知规则引擎执行规则。
3. KieContainer和KieModule
3.1 概念解释
可以理解KieContainer就是一个KieModule的容器。在KieContainer中可以包含KieModule,以及KieModule自身的一些依赖。因此KieModule可以以一中等级组织的方式被加载到KieContainer中

在KieModule中包含了若干的规则、流程、方法等。在通常的情况下KieModule就是一个名称为kmobule.xml的配置文件,此文件的配置内如例如:
<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://jboss.org/kie/6.0.0/kmodule"> <kbase name="rules.cp.discount"> <ksession name="rules.cp.discount.session" type="stateful"/> </kbase> </kmodule>
而具体的规则定义在项目的resources目录下并且与上面kmodule.xml文件中定义一个kbase元素(注意:一个kmodule.xml文件中可以定义多个kbase元素)的name属性值的子目录中,例如,如果按照上述name属性值定义了kbase后,在项目的resource目录下会存在如下的图片中的内容

├── chapter-03-classpath-tests.iml ├── pom.xml ├── src │ └── test │ ├── java │ │ └── org │ │ └── drools │ │ └── devguide │ │ └── chapter03 │ │ └── KieContainerClasspathTests.java │ └── resources │ ├── META-INF │ │ └── kmodule.xml │ └── rules │ └── cp │ └── discount │ └── classpath-discount-rules.drl
3.2 加载方式
当加载规则的时候可以通过两种方式来加载规则。
3.2.1 第一种方式:通过classpath进行规则的加载
例如在当前的目录下存在几个Maven的模块
chapter-03-classpath-tests chapter-03-kjar-parent chapter-03-kjar-premium-discounts chapter-03-kjar-simple-discounts
chapter-03-classpath-tests 其pom文件关键内容如下 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03</artifactId> <version>0.1-SNAPSHOT</version> </parent> <artifactId>chapter-03-classpath-tests</artifactId> <name>Drools 6 Developer Guide - Chapter 3: Classpath Tests</name> <packaging>jar</packaging> <dependencies> <!-- Start dependencies for the other Kie Modules --> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03-kjar-simple-discounts</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03-kjar-premium-discounts</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03-kjar-parent</artifactId> <scope>test</scope> </dependency> <!-- End dependencies for the other Kie Modules --> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>model</artifactId> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>shared</artifactId> <type>test-jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.kie</groupId> <artifactId>kie-api</artifactId> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <type>jar</type> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-library</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
chapter-03-kjar-parent 其pom文件关键内容如下 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03</artifactId> <version>0.1-SNAPSHOT</version> </parent> <artifactId>chapter-03-kjar-parent</artifactId> <name>Drools 6 Developer Guide - Chapter 3: Parent Knowledge Assets</name> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03-kjar-simple-discounts</artifactId> </dependency> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03-kjar-premium-discounts</artifactId> </dependency> </dependencies> </project>
chapter-03-kjar-premium-discounts 其pom文件关键内容如下 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03</artifactId> <version>0.1-SNAPSHOT</version> </parent> <artifactId>chapter-03-kjar-premium-discounts</artifactId> <name>Drools 6 Developer Guide - Chapter 3: Premium Discounts Knowledge Assets</name> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>model</artifactId> <type>jar</type> </dependency> </dependencies> </project>
chapter-03-kjar-simple-discounts 其pom文件关键内容如下 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.drools.devguide</groupId> <artifactId>chapter-03</artifactId> <version>0.1-SNAPSHOT</version> </parent> <artifactId>chapter-03-kjar-simple-discounts</artifactId> <name>Drools 6 Developer Guide - Chapter 3: Simple Discounts Knowledge Assets</name> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.drools.devguide</groupId> <artifactId>model</artifactId> <type>jar</type> </dependency> </dependencies> </project>
由于在chapter-03-classpath-tests模块的pom文件有对其他三个模块chapter-03-kjar-parent、chapter-03-kjar-premium-discounts和chapter-03-kjar-simple-discounts的引用,因此当通过下面的创建KieContainer时,会加载这四个模块中的所定义的所有规则
@Test public void loadingRulesFromLocalKieModule() { System.out.println("### Running loadingRulesFromLocalKieModule() Test ###"); KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.newKieClasspathContainer(); Results results = kContainer.verify(); results.getMessages().stream().forEach((message) -> { System.out.println(">> Message ( "+message.getLevel()+" ): "+message.getText()); }); assertThat(false, is(results.hasMessages(Message.Level.ERROR))); kContainer.getKieBaseNames().stream().map((kieBase) -> { System.out.println(">> Loading KieBase: "+ kieBase ); return kieBase; }).forEach((kieBase) -> { kContainer.getKieSessionNamesInKieBase(kieBase).stream().forEach((kieSession) -> { System.out.println("\t >> Containing KieSession: "+ kieSession ); }); }); // Let's load the configurations for the kmodule.xml file // defined in the /src/test/resources/META-INF/ directory KieSession kieSession = kContainer.newKieSession("rules.cp.discount.session"); Customer customer = new Customer(); customer.setCategory(Customer.Category.BRONZE); Order order = new Order(); order.setCustomer(customer); kieSession.insert(customer); kieSession.insert(order); int fired = kieSession.fireAllRules(); assertThat(1, is(fired)); assertThat(5.0, is(order.getDiscount().getPercentage())); System.out.println("### Finished loadingRulesFromLocalKieModule() Test ###"); } 输出如下: ### Running loadingRulesFromLocalKieModule() Test ### >> Loading KieBase: rules.simple >> Containing KieSession: rules.simple.discount >> Containing KieSession: rules.simple.sl.discount >> Loading KieBase: rules.cp.discount >> Containing KieSession: rules.cp.discount.session >> Loading KieBase: rules.premium >> Containing KieSession: rules.premium.discount >> Loading KieBase: discount >> Containing KieSession: rules.discount.all ### Finished loadingRulesFromLocalKieModule() Test ### Process finished with exit code 0
3.2.2 第二种方式:通过Maven提供的工具进行加载(或者称之为Kie-CI)
通过Maven方式进行加载与通过classpath进行加载的最大不同在于,在pom文件中不需要依赖要加载的其他模块的GAV(GroupId, ArtifactId, and Version),取而代之的时需要加入下面的GAV
<dependency> <groupId>org.kie</groupId> <artifactId>kie-ci</artifactId> <scope>test</scope> </dependency>
此时就可以通过GAV方式来精确指定要加载的模块中的规则,如下所示
KieContainer kContainer = ks.newKieContainer(ks.newReleaseId( "org.drools.devguide", "chapter-03-kjar-simple-discounts", "1.0.0"));
- KieModule、KieBase和KieSession
KieBase是什么呢?KieBase就是一个知识仓库,包含了若干的规则、流程、方法等,在Drools中主要就是规则和方法,KieBase本身并不包含运行时的数据之类的,如果需要执行规则KieBase中的规则的话,就需要根据KieBase创建KieSession。在KIESession中加载了在Drools规则引擎中真正要运行的规则rules
- KieHelper说明
有时候可以通过KieHelper来创建一个KieSession,例如
private KieSession createKieSessionFromDRL(String drl) { KieHelper kieHelper = new KieHelper(); kieHelper.addContent(drl, 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); for (Message message : messages) { System.out.println("Error: " + message.getText()); } throw new IllegalStateException("Compilation errors were found. Check the logs."); } return kieHelper.build().newKieSession(); }
这个方法的实现很直接。它通过KieHelper来编译一个字符串形式规则。并且kieHelper可以在编译期间检查规则的错误,如果有错误的话,可以通过Results进行输出。如果没有错误的话,直接创建一个KieSession。
KieHelper工具类并不是Drools对外开房的API的一部分。这个类提供了一些很方便的可以省略很多模板代码的方式来创建KieSession。由于这个类并不是Kie-api(Drools中的一个依赖)的一部分,因此虽然其使用方便,但是当使用Drools最新的版本时有可能出现向后不兼容的问题(意思是,在最新的Drools版本中有可能会删除或者禁用掉这个类)
『Mastering JBoss Drools 6 for Developers P195』
KieHelper这个类提供了很多不同的方法可以向KieContainer中添加资源(例如规则),然后验证,最终创建出一个KieContainer。对于KieHelper的一个经典使用方式的代码片段类似上面的代码片段。
KieHelper不仅仅用来单元或者继承测试。你的应用可以使用KieHelper以细粒度的(fine-grained)方式类控制你所需要加入到KieContainer中的资源。典型的使用场景例如:你可以通过KieHelper来向KieContainer中动态加载字符串形式的规则
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接
本文链接:http://www.choupangxia.com/2021/06/06/drools-core-concepts/