如何实现规则引擎动态加载规则配置文件(drl文件)

1、简介

        在使用Drools规则引擎中,项目加载drools中的规则文件,需要保存在resources目录下才能被加载,如果使用自定义的路径存放drl文件,要实现动态加载该如何实现,本文将使用springboot框架集成Drools进行分享。

2、实现过程
2.1、pom.xml依赖

为了在springboot中使用Drools,需要引入下列依赖:

<!--drools规则引擎-->
<dependency>
	<groupId>org.drools</groupId>
	<artifactId>drools-core</artifactId>
	<version>7.6.0.Final</version>
</dependency>
<dependency>
	<groupId>org.drools</groupId>
	<artifactId>drools-compiler</artifactId>
	<version>7.6.0.Final</version>
</dependency>
<dependency>
	<groupId>org.drools</groupId>
	<artifactId>drools-templates</artifactId>
	<version>7.6.0.Final</version>
</dependency>
<dependency>
	<groupId>org.kie</groupId>
	<artifactId>kie-api</artifactId>
	<version>7.6.0.Final</version>
</dependency>
<dependency>
	<groupId>org.kie</groupId>
	<artifactId>kie-internal</artifactId>
	<version>7.6.0.Final</version>
</dependency>
<dependency>
	<groupId>org.kie</groupId>
	<artifactId>kie-spring</artifactId>
	<version>7.6.0.Final</version>
</dependency>
 2.2、新建动态加载类

        注意:这个地方需要配置正确规则文件资源路径

package com.test;

import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DroolsDynamicService {

    @Value("${drools.file.path}")
    private String rulesPath;

    public KieSession getKieSession() throws IOException {
        KieContainer kieContainer = loadContainer();
        return kieContainer.newKieSession();
    }
    private KieContainer loadContainer() throws IOException {
        // 检查规则目录是否存在
        Path rulesDir = Paths.get(rulesPath);
        log.info("Loading rules from directory: {}", rulesDir.toAbsolutePath());
        if (!Files.exists(rulesDir)) {
            log.info("Rules directory does not exist, creating: {}", rulesDir.toAbsolutePath());
            Files.createDirectories(rulesDir);
        }
        // 列出目录中的所有文件
        log.info("Files in directory {}:", rulesDir.toAbsolutePath());
        Files.list(rulesDir).forEach(path -> log.info("Found file: {}", path));

        // 遍历规则目录下的所有.drl文件
        List<Path> ruleFiles = Files.walk(rulesDir)
                .filter(path -> path.toString().endsWith(".drl"))
                .collect(Collectors.toList());

        if (ruleFiles.isEmpty()) {
            log.warn("No .drl files found in directory: {}", rulesDir.toAbsolutePath());
        }
        // 创建 KieFileSystem
        KieServices kieServices = KieServices.Factory.get();
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        for (Path path : ruleFiles) {
            try {
                log.info("Loading rule file: {}", path.toAbsolutePath());
                File ruleFile = path.toFile();
                if (ruleFile.exists() && ruleFile.isFile()) {
                    String content = new String(Files.readAllBytes(path));
                    // 使用正确的资源路径加载规则
                    String resourcePath = "src/main/resources/rules/" + ruleFile.getName();
                    log.info("Loading rule with resource path: {}", resourcePath);
                    kieFileSystem.write(resourcePath, content);
                    log.info("Successfully loaded rule file: {}", path.getFileName());
                } else {
                    log.warn("Rule file does not exist or is not a file: {}", path.toAbsolutePath());
                }
            } catch (Exception e) {
                log.error("Error loading rule file: " + path.toAbsolutePath(), e);
            }
        }
        // 构建 KieModule
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
        kieBuilder.buildAll();
        Results results = kieBuilder.getResults();
        if (results.hasMessages(Message.Level.ERROR)) {
            String errors = results.toString();
            log.error("Build Errors:\n{}", errors);
            throw new RuntimeException("Build Errors:\n" + errors);
        }
        // 创建 KieContainer
        KieContainer container = kieServices.newKieContainer(kieBuilder.getKieModule().getReleaseId());
        // 验证规则是否被加载
        if (container.verify().hasMessages(Message.Level.ERROR)) {
            String errors = container.verify().toString();
            log.error("Container verification errors:\n{}", errors);
            throw new RuntimeException("Container verification errors:\n" + errors);
        }
        // 打印加载的规则信息
        log.info("Loaded rules in KieBase:");
        container.getKieBase().getKiePackages().forEach(pkg -> {
            log.info("Package: {}", pkg.getName());
            pkg.getRules().forEach(rule -> {
                log.info("  Rule: {}", rule.getName());
            });
        });
        log.info("Successfully created KieContainer with {} rule files", ruleFiles.size());
        return container;
    }
}
2.3、配置文件(application.yml)
drools:
  file:
    path: D:\drools_file
2.4、使用

        为了能保证动态加载,在使用的时候,每获取一次 KieSession  就加载一次drl文件就可以解决

@Service
public class Test{
	@Autowired
	private DroolsDynamicService droolsDynamicService;

	public void test(){
		KieSession kieSession = null;
		try {
			kieSession = droolsDynamicService.getKieSession();
		} catch (IOException e) {
			throw new RuntimeException("获取KieSession异常:" + e.getMessage());
		}
		User user = new User();
		kieSession.insert(user);
		kieSession.fireAllRules();
		kieSession.dispose();
	}

}
3、总结

        Drools对于规则变化的场景,能够在不该写代码的情况下,通过配置规则配置文件,实现逻辑变动,对于Drools应用还有很多需要注意的地方,本文只是记录博主在开发过程中踩过的一个坑。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知其_所以然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值