1.说明

为了更好的在项目中使用Drools,
需要把Drools集成到Spring Boot,
下面介绍集成的方法,
并且开发简单的Demo和测试用例。

2.创建Maven工程

pom.xml工程信息:

<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>
<groupId>com.ai.prd</groupId>
<artifactId>drools-spring-boot-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>Drools integrats into the Spring Boot</description>
</project>

3.引入Spring Boot相关依赖

引入spring-boot-starter-web作为Web工程,对外提供Rest服务,
引入spring-boot-starter-log4j2日志框架,打印测试匹配结果,
引入spring-boot-starter-test测试框架,开发Junt5测试用例:

<properties>
<spring-boot.version>2.3.1.RELEASE</spring-boot.version>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<!-- 单元测试不使用Junit4,使用Junit5 -->
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

4.引入Drools相关依赖

通过kie-spring引入Drools相关的jar包,
其依赖的spring版本都排除掉,
以上一步的spring boot依赖为准。

<properties>
<drools.version>7.47.0.Final</drools.version>
</properties>
<dependencies>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${drools.version}</version>
<exclusions>
<!-- 依赖的spring版本全部以spring boot依赖的为准 -->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

5.开发启动类

启动类DroolsApplication.java:

package com.ai.prd.drools;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class DroolsApplication {
public static void main(String[] args) {
SpringApplication.run(DroolsApplication.class, args);
}
}

6.开发Rest服务

操作的对象Person,
Person.java:

package com.ai.prd.drools.entity;

public class Person {
private String name; private int age;
}

对外提供的Rest服务,
可以对Person对象进行规则匹配,
提供了两个接口,
单个和批量的操作接口:
PersonRuleController.java:

package com.ai.prd.drools.controller;

import java.util.List;

import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import com.ai.prd.drools.entity.Person; @RestController
@RequestMapping("rule/person")
public class PersonRuleController { @Autowired
private KieContainer kieContainer; @PostMapping("one")
public void fireAllRules4One(@RequestBody Person person) {
KieSession kSession = kieContainer.newKieSession();
try {
kSession.insert(person);
kSession.fireAllRules();
} finally {
kSession.dispose();
}
} @PostMapping("list")
public void fireAllRules4List(@RequestBody List<Person> persons) {
KieSession kSession = kieContainer.newKieSession();
try {
for (Person person : persons) {
kSession.insert(person);
}
kSession.fireAllRules();
} finally {
kSession.dispose();
}
}
}

7.初始化Drools

在上面PersonRuleController中需要用到KieContainer,
这个必须在Spring中先初始化才能使用,
相关功能由DroolsAutoConfiguration.java提供:

package com.ai.prd.drools.config;

import java.io.IOException;

import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieModule;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.ReleaseId;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver; /**
* 配置Drools的服务类,方便在Rest接口中调用。 该类负责加载具体的drl规则文件, 不再需要kmodule.xml配置文件了。
*/
@Configuration
public class DroolsAutoConfiguration { private static final String RULES_PATH = "rules/com/ai/prd/"; @Bean
@ConditionalOnMissingBean(KieFileSystem.class)
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
}
return kieFileSystem;
} private Resource[] getRuleFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
} @Bean
@ConditionalOnMissingBean(KieContainer.class)
public KieContainer kieContainer() throws IOException {
final KieRepository kieRepository = getKieServices().getRepository(); kieRepository.addKieModule(new KieModule() {
@Override
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
}); KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll(); return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
} private KieServices getKieServices() {
return KieServices.Factory.get();
} @Bean
@ConditionalOnMissingBean(KieBase.class)
public KieBase kieBase() throws IOException {
return kieContainer().getKieBase();
} // 不能反复被使用,释放资源后需要重新获取。
// @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
@ConditionalOnMissingBean(KieSession.class)
public KieSession kieSession() throws IOException {
return kieContainer().newKieSession();
} @Bean
@ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)
public KModuleBeanFactoryPostProcessor kiePostProcessor() {
return new KModuleBeanFactoryPostProcessor();
}
}

8.开发规则文件

在DroolsAutoConfiguration中指定了drl规则文件
所在目录rules/com/ai/prd/,
在src/main/resources/rules/com/ai/prd/目录下新建文件
ai-rules.drl:

package com.ai.prd

import com.ai.prd.drools.entity.Person;
import com.ai.prd.drools.action.PersonRuleAction; // 根据名字匹配指定的人
rule "1.find target person"
when
$p : Person( name == "bob" )
then
PersonRuleAction.doParse($p, drools.getRule());
System.out.println("Rule name is [" + drools.getRule().getName() + "]");
System.out.println("Rule package is [" + drools.getRule().getPackageName() + "]");
end // 根据年龄匹配找到打工人
rule "2.find the work person"
when
$p : Person( age >= 25 && age < 65 )
then
System.out.println( $p + " is a work person!" );
end

规则1匹配名字为bob的人,并且调用工具类PersonRuleAction打印相关日志,
同时打印规则的名称和包路径到控制台。
规则2匹配年龄在25到65之间的打工人,
然后把匹配到的人直接打印到控制台。

9.规则处理类

PersonRuleAction.java在匹配到相应规则时被调用,
此处仅实现日志打印的功能:

package com.ai.prd.drools.action;

import org.drools.core.definitions.rule.impl.RuleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.ai.prd.drools.entity.Person; /**
* 触发Person相关的规则后的处理类
*
* @author yuwen
*
*/
public class PersonRuleAction {
private static Logger LOG = LoggerFactory.getLogger(PersonRuleAction.class); // 目前只实现记录日志功能
public static void doParse(Person person, RuleImpl rule) {
LOG.debug("{} is matched Rule[{}]!", person, rule.getName());
}
}

10.新建日志配置文件

在src/main/resources目录下,
新建日志配置文件Log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RollingFile name="RuleResultFile"
fileName="log/rule_result.log"
filePattern="log/backup/rule_result-%i.log">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%l] - %msg%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
</Policies>
<DefaultRolloverStrategy max="10" />
</RollingFile>
</Appenders>
<Loggers>
<Logger name="com.ai.prd.drools.action" level="DEBUG"
additivity="true">
<AppenderRef ref="RuleResultFile" />
</Logger>
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>

日志文件配置后,
PersonRuleAction类打印的日志
不仅会输出到log/rule_result.log,
也会输出到控制台。

11.开发Junit5测试用例

针对上面PersonRuleController提供的Rest接口,
开发两个Junit5的测试用例,
在src/test/java/目录下
创建PersonRuleControllerTest.java:

package com.ai.prd.drools.controller;

import java.util.Arrays;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import com.ai.prd.drools.entity.Person; @SpringBootTest
public class PersonRuleControllerTest { @Autowired
PersonRuleController controller; @Test
public void testOnePerson() {
Person bob = new Person();
bob.setName("bob"); controller.fireAllRules4One(bob);
} @Test
public void testTwoPerson() {
Person bob = new Person();
bob.setAge(33); Person other = new Person();
other.setAge(88); controller.fireAllRules4List(Arrays.asList(bob, other));
}
}

12.运行测试用例

PersonRuleControllerTest执行后,
控制台输出:

14:22:04.851 [main] WARN  org.drools.compiler.kie.builder.impl.KieBuilderImpl - File 'rules/com/ai/prd/ai-rules.drl' is in folder 'rules/com/ai/prd' but declares package 'com.ai.prd'. It is advised to have a correspondance between package and folder names.
14:22:06.753 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
14:22:07.063 [main] INFO com.ai.prd.drools.controller.PersonRuleControllerTest - Started PersonRuleControllerTest in 3.279 seconds (JVM running for 4.452)
14:22:07.279 [main] DEBUG com.ai.prd.drools.action.PersonRuleAction - Person [name=bob, birthDay=null, age=0, address=null] is matched Rule[1.find target person]!
Rule name is [1.find target person]
Rule package is [com.ai.prd]
Person [name=null, birthDay=null, age=33, address=null] is a work person!
14:22:07.649 [SpringContextShutdownHook] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'

13.错误解决

cannot be cast to org.drools.compiler.kie.builder.impl.InternalKieModule
大概率是rule规则文件有问题,
格式,中英文字符,语法等问题,
请确保规则文件正确。
可以安装相应插件打开规则文件,
请参考:Drools的Eclipse_IDEA插件安装

14.参考文章

Drools规则引擎 系列教程(一)SpringBoot整合 & 快速集成上手《Drools7.0.0.Final规则引擎教程》之Springboot集成Drools创建Maven工程

Drools集成SpringBoot的更多相关文章

  1. Drools集成SpringBootStarter

    1.说明 基于fast-drools-spring-boot-starter, 能够方便的将规则引擎Drools集成到Spring Boot, 基于前面介绍过的文章Drools集成SpringBoot ...

  2. Spring Maven项目集成Springboot

    Maven管理的Spring项目,准备集成Springboot做接口 1.Springboot对Spring有版本要求 我用的Springboot版本:1.4.5.RELEASE,对应Spring的版 ...

  3. 实战:docker搭建FastDFS文件系统并集成SpringBoot

    实战:docker搭建FastDFS文件系统并集成SpringBoot 前言 15年的时候,那时候云存储还远远没有现在使用的这么广泛,归根结底就是成本和安全问题,记得那时候我待的公司是做建站开发的,前 ...

  4. 集成Springboot+MyBatis+JPA

    1.前言 Springboot最近可谓是非常的火,本人也在项目中尝到了甜头.之前一直使用Springboot+JPA,用了一段时间发现JPA不是太灵活,也有可能是我不精通JPA,总之为了多学学Spri ...

  5. eclipse集成springboot 插件(离线安装,含解决Cannot complete the install because one or more required items could)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/li18310727696/article/details/81071002首先,确认eclipse的 ...

  6. fastdfs基本安装流程和集成springboot总结

    FastDFS介绍 1.简介 FastDFS 是一个开源的高性能分布式文件系统(DFS). 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡.主要解决了海量数据存储问题,特别适合以 ...

  7. netty集成springboot

    一 前言 springboot 如何集成netty实现mapper调用不为null的问题让好多读者都头疼过,知识追寻者发了一点时间做了个基本入门集成应用给读者们指明条正确的集成方式,我相信,只要你有n ...

  8. Flowable实战(二)集成Springboot

    1.创建Springboot项目   打开IDEA,通过File -> New -> Project- -> Spring Initializr 创建一个新的Springboot项目 ...

  9. ElasticSearch集成SpringBoot与常见使用方法

    目录 一.导包 二.核对导入的ES版本 修改导入版本 三.写配置类 四.开始测试 索引操作 1.创建索引 2.查看索引是否存在 3.删除索引 文档操作 1.添加文档 2.查看文档是否存在 3.修改文档 ...

随机推荐

  1. idea2019.2安裝MybatisCodeHelper插件

    1. 下载MybatisCodeHelper插件 下载已破解的插件压缩包,一定注意校验sha1sum!!! 在IDEA中本地安装插件 激活方法(自2.7.3):IDEA顶部菜单:Tools -> ...

  2. SpringBoot(3):SpringData 数据访问

    一. 简介 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架:其主要目标是 使得对数据的访问变得方便快捷.对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系 ...

  3. Airtest结合tidevice实现IOS自动化测试

    这篇博文内容,是基于之前的配置而来的.我们可以先回顾一下之前博文,Windows搭建mac黑苹果系统:WebDriverAgent重签名爬坑记 . 今天来分享下如何通过 tidevice实现IOS自动 ...

  4. CPU的中断

    目录 一.简介 二.具体 方式 硬中断 软中断 中断切换 网卡中断 三.中断查看 一.简介 中断其实就是由硬件或软件所发送的一种称为IRQ(中断请求)的信号.中断允许让设备,如键盘,串口卡,并口等设备 ...

  5. SimpleCursorAdapter 原理和实例

    SimpleCursorAdapter 1. 原理参见下面代码注释 Cursor cursor = dbHelper.fetchAllCountries(); //cursor中存储需要加载到list ...

  6. [BUUCTF]PWN——jarvisoj_tell_me_something

    jarvisoj_tell_me_something 附件 步骤: 例行检查,64位程序,开启了NX保护 运行一下程序,看看程序的大概流程 64位ida载入,shift+f12检索程序里的字符串 看到 ...

  7. PMP过程组与知识领域

    过程组知识领域 启动 规划 执行 监控 结尾 整合管理 制定项目章程 制定项目计划 指导与管理项目工作 监控项目工作 结束项目过程或阶段 项目管理知识 实施整体变更控制 范围管理 规划范围管理 确认范 ...

  8. Flask与Django的比较

    Flask与Django的区别 Flask Flask确实很"轻",不愧是Micro Framework,从Django转向Flask的开发者一定会如此感慨,除非二者均为深入使用过 ...

  9. Sharepoint 列表分页开发

    虽然现在linq技术对列表操作都是对实体操作了,但是linq有一点不好,那就是分页舞从下手,假如查出满足条件的记录有1万条,而在分页的时候我每次只需要显示10条,那么我每次点击下一页的时候都查询的是1 ...

  10. [C# Expression] 之动态创建表达式

    上一篇中说到了 Expression 的一些概念性东西,其实也是为了这一篇做知识准备.为了实现 EFCore 的多条件.连表查询,简化查询代码编写,也就有了这篇文章.   在一些管理后台中,对数据进行 ...