IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Drools7 动态更新规则 -> 正文阅读

[Java知识库]Drools7 动态更新规则

动态更新规则

上一章节讲述了 Drools7 和 Springboot2 集成使用,集成工作相对简单、可以快速开发。但是缺点也很明显,规则和配置文件绑定在项目中(耦合度太高)。如果你不需要修改规则文件,这种方式还是可以采纳的。此篇讲述如何从数据库中加载规则文件,动态加载更新规则。

KieHelper

Drools 中提供了 KieHelper ,可以动态添加规则,并且创建新的 kieContainer 返回。

// 借助 kieHelper 添加规则
KieHelper kieHelper = new KieHelper();
// 动态添加规则内容
kieHelper.addContent(content, ResourceType.DRL);
// 校验规则是否异常
Results results = kieHelper.verify();
if (results.hasMessages(Message.Level.ERROR)) {
    System.out.println(results.getMessages());
    throw new IllegalStateException("### errors ###");
}
// 重置 kieContainer
kieContainer = kieHelper.getKieContainer();

更新规则实现

添加依赖
<!--mybatis-plus启动器,规则文件放到数据库-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.43</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
<!--drools-->
<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>
表结构设计

两条规则分别对 Person 名字和年龄进行判断;
第一条:如果name=“bob” 则打印规则名称,规则包名,和 name;
第二条:如果name=“bob” 且年龄是25和65之间则打印 is a work person;

DROP TABLE IF EXISTS `rule`;
CREATE TABLE `rule`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `rule` VALUES (1, '1.find target person', 'package rules.rules\r\n\r\nimport com.skystep.drools.person.PersonRuleAction\r\nimport com.skystep.drools.person.entity.Person\r\nimport com.skystep.drools.person.service.PersonService\r\nimport com.skystep.drools.person.service.PersonServiceImpl\r\n\r\n// 根据名字匹配指定的人\r\nrule \"1.find target person\"\r\n    when\r\n        $p : Person( name == \"bob\" )\r\n    then\r\n        PersonRuleAction.doParse($p, drools.getRule());\r\n        System.out.println(\" Rule name is [\" + drools.getRule().getName() + \"] \");\r\n        System.out.println(\" Rule package is [\" + drools.getRule().getPackageName() + \"] \");\r\n        PersonService personService = new PersonServiceImpl();\r\n        personService.hello(\" 我的名字是: \" + $p.getName());\r\nend');
INSERT INTO `rule` VALUES (2, '2.find the work person', 'package rules.rules\r\n\r\nimport com.skystep.drools.person.PersonRuleAction\r\nimport com.skystep.drools.person.entity.Person\r\nimport com.skystep.drools.person.service.PersonService\r\nimport com.skystep.drools.person.service.PersonServiceImpl\r\n\r\n// 根据年龄匹配找到打工人\r\nrule \"2.find the work person\"\r\n    when\r\n        $p : Person( age >= 25 && age < 65 )\r\n    then\r\n        System.out.println( $p + \" is a work person!\" );\r\nend');

默认配置 Drools
@Configuration
public class RuleEngineConfig {
    private static final String RULES_PATH = "rules/";

    @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();
    }
}
Drools 动态加载规则

RuleService 提供 getRules 方法从数据库中获取所有的规则,循环加载到 kieHelper。Spring 启动注入 RuleEngineService 时会提前初始化,执行 reload 函数。因此此时内容中存在的规则是从数据库中加载的规则。

@Service
@Slf4j
public class RuleEngineService {

    @Autowired
    private KieContainer kieContainer;

    // 规则服务
    @Autowired
    RuleService ruleService;

    @PostConstruct
    public void init() {
        reload();
    }

    public KieContainer getKieContainer() {
        return kieContainer;
    }


    public void reload() {
        // 借助 kieHelper 添加规则
        KieHelper kieHelper = new KieHelper();
        // 从数据库中获取所有的规则
        List<Rule> rules = ruleService.getRules();
        if (!CollectionUtils.isEmpty(rules)) {
            // 循环加载所有的规则
            for (Rule rule : rules) {
                String content = rule.getContent();
                kieHelper.addContent(content, ResourceType.DRL);
            }
        }
        // 校验规则是否异常
        Results results = kieHelper.verify();

        if (results.hasMessages(Message.Level.ERROR)) {
            System.out.println(results.getMessages());
            throw new IllegalStateException("### errors ###");
        }
        // 重置容器
        kieContainer = kieHelper.getKieContainer();
    }
}
添加接口
@RestController
@RequestMapping("rule")
public class PersonRuleController {
    @Autowired
    private RuleEngineService ruleEngineService;

    @PostMapping("test")
    public void fireAllRules4One(@RequestBody Person person) {
        KieSession kSession = ruleEngineService.getKieContainer().newKieSession();
        try {
            kSession.insert(person);
            kSession.fireAllRules(new RuleNameEqualsAgendaFilter(""));
        } finally {
            kSession.dispose();
        }
        return;
    }

    @GetMapping("reload")
    public void reload() {
        ruleEngineService.reload();
    }
}
验证

POST /rule/test,请求参数:

{"name": "bob"}
Rule name is [1.find target person] 
Rule package is [rules.rules] 
2022-07-02 23:31:58.580  INFO 23540 --- [nio-8080-exec-6] c.s.d.person.service.PersonServiceImpl   :  我的名字是: bob

命中了数据库中的第一条规则。name=“bob”,

POST /rule/test,请求参数:

{"name": "bob", "age": 33}
Rule name is [1.find target person] 
Rule package is [rules.rules] 
2022-07-02 23:39:49.991  INFO 23540 --- [nio-8080-exec-9] c.s.d.person.service.PersonServiceImpl   :  我的名字是: bob
Person(name=bob, age=33) is a work person!

命中了数据库中的两条记录

动态添加规则

数据库增加一条规则,判断名称是否是 skystep, 如果name=“skystep” 则打印规则名称,规则包名,和 name。

INSERT INTO `rule` VALUES (3, '3.find target person', 'package rules.rules\r\n\r\nimport com.skystep.drools.person.PersonRuleAction\r\nimport com.skystep.drools.person.entity.Person\r\nimport com.skystep.drools.person.service.PersonService\r\nimport com.skystep.drools.person.service.PersonServiceImpl\r\n\r\n// 根据名字匹配指定的人\r\nrule \"3.find target person\"\r\n    when\r\n        $p : Person( name == \"skystep\" )\r\n    then\r\n        PersonRuleAction.doParse($p, drools.getRule());\r\n        System.out.println(\" Rule name is [\" + drools.getRule().getName() + \"] \");\r\n        System.out.println(\" Rule package is [\" + drools.getRule().getPackageName() + \"] \");\r\n        PersonService personService = new PersonServiceImpl();\r\n        personService.hello(\" 我的名字是: \" + $p.getName());\r\n end');

GET /rule/reload 重新加载规则,

POST /rule/test,请求参数:

{"name": "skystep"}
Rule name is [3.find target person] 
 Rule package is [rules.rules] 
2022-07-03 00:00:49.148  INFO 23540 --- [nio-8080-exec-2] c.s.d.person.service.PersonServiceImpl   :  我的名字是: skystep

命中了数据库中的第条3规则,说明动态添加的第三条规则已经加载到内存,并且成功匹配。

源码下载

https://download.csdn.net/download/skystep/85870731
Drools7 + Springboot2 动态更新规则。
规则存储到数据库MYSQL,动态从数据库中获取规则进行加载。
运行前请自行修改MYSQL配置

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:25:28  更:2022-07-05 23:27:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 15:24:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码