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. SpringMVC(4):文件上传与下载

    一,文件上传 文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理 ...

  2. 3.3 GO字符串处理

    strings方法 index 判断子字符串或字符在父字符串中出现的位置(索引)Index 返回字符串 str 在字符串 s 中的索引( str 的第一个字符的索引),-1 表示字符串 s 不包含字符 ...

  3. 使用Spring JDBC连接数据库(以SQL Server为例)

    一.配置Spring JDBC 1.导入相关jar包 (略) 2.配置文件applicationContext.xml <?xml version="1.0" encodin ...

  4. 【力扣】649. Dota2 参议院

    Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇) Dota2 参议院由来自两派的参议员组成.现在参议院希望对一个 Dota2 游戏里的改变作出决定.他们以一个基于轮为过程的投 ...

  5. 培训班输出的大量学员,会对IT行业产生哪些影响?

    先说下会有哪些影响呢?   1 可能也就是些大城市的,规模比较大的,口碑比较好的培训学校输出的码农才能入行,而且能做长久.一些线上的所谓培训机构,或者小城市的培训学校,输出的能入行的码农,其实规模很有 ...

  6. Spring MVC环境搭建和配置

    1. 创建Dynamic web project 2. 修改WEB-INF/web.xml,内容如下: <?xml version="1.0" encoding=" ...

  7. 用Word做表,总会多出一页来?(Word技巧集团)

    用Word做表的同学都有这样的体验,表格后面都会多出一行,默认的,去都去不掉.如果一个表刚好做到一页的最下面,嗯,那就多出一页来,如下图: 这一页,多不多余啊,讨不讨厌啊,可不可恶啊--可是Word同 ...

  8. CF94A Restoring Password 题解

    Content 有一个 \(80\) 位的 \(01\) 字符串,由 \(8\) 个长度为 \(10\) 的 \(01\) 字符串组成,每个小字符串分别对应一个数字.现在,给出这个字符串和 \(0\) ...

  9. LuoguB2105 矩阵乘法 题解

    Content 给定一个 \(n\times m\) 的矩阵 \(A\) 和一个 \(m\times k\) 的矩阵 \(B\),求两个矩阵相乘得到的矩阵. \(n\times m\) 的矩阵 \(A ...

  10. CF1494B Berland Crossword 题解

    Content 有一种叫做 Berland crossword 的拼图游戏.这个拼图由 \(n\) 行 \(n\) 列组成,你可以将里面的一些格子涂成黑色.现在给出 \(T\) 个这样的拼图,每个拼图 ...