阅读 96

Drools集成SpringBootStarter

1.说明

基于fast-drools-spring-boot-starter,
能够方便的将规则引擎Drools集成到Spring Boot,
基于前面介绍过的文章
Drools集成SpringBoot,
进一步改造成使用fast-drools-spring-boot-starter的项目。

2.fast-drools-spring-boot-starter

项目地址:
Fast Drools

项目特性:

  • SpringBoot与Drools快速整合,不需要配置繁琐的kmodule.xml,也不需要自己编写代码初始化Drools
  • 指定文件名执行评估规则,更加直观的流程分析
  • 规则文件动态加载
  • 规则文件分组控制
  • 使用NIO的文件映射,更快速的文件的读写
  • 基于缓存的规则文件控制,更高效的规则评估
  • 支持各种路径格式
  • 支持xls和xlsx格式的规则表文件
  • 日志监控流程中规则与评估对象的动态
  • 执行速度与性能的极致,且可定制

注意:
这是第三方个人开发的开源项目,
不推荐在正式项目中使用,
但是作者已经把jar包等发布到了阿里云的仓库,
所以国内的同学使用起来还是比较方便的。

3.创建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-fast-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <description>Based on fast-drools-spring-boot-starter, Drools integrats into the Spring Boot</description>
</project>

4.引入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>

5.引入Drools相关依赖

引入fast-drools-spring-boot-starter即可:

<properties>
    <fast.drools.version>8.0.7</fast.drools.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.github.hongwen1993</groupId>
        <artifactId>fast-drools-spring-boot-starter</artifactId>
        <version>${fast.drools.version}</version>
    </dependency>
</dependencies>

6.开发启动类

启动类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);
    }
}

7.操作对象Person

下面会对Person对象进行规则过滤,
这里给出定义Person.java:

package com.ai.prd.drools.entity;

public class Person {
    private String name;

    private int age;
}

8.开发规则文件

在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相关的规则后的处理类
 */
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.配置application.yml

在src/main/resources下新建application.yml:

server:
  port: 5117
  
# 指定规则文件文件夹,会自动扫描该目录下所有规则文件,决策表,以及CSV文件
spring:
  drools:
    path: classpath:rules/**/*.drl
    # 可以指定全局的mode,选择stream或cloud
    mode: stream
    # 指定规则文件自动更新的周期,单位秒,默认30秒扫描一次
    update: 10
    listener: on 

指定了应用运行的端口,
以及Drools相关的配置。

11.新建日志配置文件

在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,
也会输出到控制台。

12.开发Junit5测试用例

针对上面规则文件中配置的规则,
开发两个Junit5的测试用例,
在src/test/java/目录下
创建DroolsApplicationTest.java:

package com.ai.prd.drools;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.ai.prd.drools.entity.Address;
import com.ai.prd.drools.entity.Person;
import com.drools.core.KieTemplate;

@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class DroolsApplicationTest {

    @Autowired
    private KieTemplate kieTemplate;

    private KieSession kSession;

    @BeforeAll
    public void initKieSession() {
        // 每次测试都要重新获取kSession
        // 同时可以指定要加载的规则文件
        kSession = kieTemplate.getKieSession("ai-rules.drl");
    }

    @AfterAll
    public void runDispose() {
        // 全部测试用例执行完毕后,需要手动释放资源
        kSession.dispose();
    }

    @Test
    public void test1findTargetPerson() {
        Person bob = new Person();
        bob.setName("bob");
        kSession.insert(bob);

        Person other = new Person();
        other.setName("other1");
        kSession.insert(other);

        int rules = kSession.fireAllRules();
        // 按照规则1只有bob能够匹配上
        assertEquals(1, rules);
    }

    @Test
    public void test2findWorkPerson() {
        Person bob = new Person();
        bob.setAge(33);
        kSession.insert(bob);

        Person other = new Person();
        other.setAge(88);
        kSession.insert(other);

        int rules = kSession.fireAllRules();
        assertEquals(1, rules);
    }

注意这里的KieTemplate是fast-drools-spring-boot-starter提供的,
而不是以前kie-spring提供的KieContainer了。

13.运行测试用例

DroolsApplicationTest执行后,
控制台输出:

15:46:02.441 [main] INFO  com.ai.prd.drools.DroolsApplicationTest - Starting DroolsApplicationTest on yuwen-asiainfo with PID 3836 (started by yuwen in D:\Code\Work\drools\drools-demos\drools-fast-demo)
15:46:02.443 [main] INFO  com.ai.prd.drools.DroolsApplicationTest - No active profile set, falling back to default profiles: default
15:46:03.387 [main] INFO  org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
15:46:03.701 [main] INFO  com.ai.prd.drools.DroolsApplicationTest - Started DroolsApplicationTest in 1.524 seconds (JVM running for 2.704)
15:46:04.081 [main] WARN  org.drools.compiler.kie.builder.impl.KieBuilderImpl - File 'file0.drl' is in folder '' but declares package 'com.ai.prd'. It is advised to have a correspondance between package and folder names.
15:46:04.911 [main] WARN  org.drools.compiler.kie.builder.impl.KieBuilderImpl - File 'file0.drl' is in folder '' but declares package 'com.ai.prd'. It is advised to have a correspondance between package and folder names.
15:46:05.723 [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!
15:46:05.748 [SpringContextShutdownHook] INFO  org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐