在《Drools7.0.0.Final规则引擎教程》之Springboot集成中介绍了怎样将Drools与Springboot进行集成,本篇博客介绍一下集成之后,如何实现从数据库读取规则并重新加载规则的简单demo。因本章重点介绍的是Drools相关操作的API,所以将查询数据库部分的操作省略,直接使用数据库查询出的规则代码来进行规则的重新加载。另外,此示例采用访问一个http请求来进行重新加载,根据实际需要可考虑定时任务进行加载等扩展方式。最终的使用还是要结合具体业务场景来进行分析扩展。
整体项目结构
上图是基于intellij maven的项目结构。其中涉及到springboot的Drools集成配置类,重新加载规则类。一些实体类和工具类。下面会抽出比较重要的类进行分析说明。
DroolsAutoConfiguration
@Configuration public class DroolsAutoConfiguration {
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() { public ReleaseId getReleaseId() { return kieRepository.getDefaultReleaseId();
}
});
KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
KieContainer kieContainer = getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
KieUtils.setKieContainer(kieContainer); return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
}
private KieServices getKieServices() { return KieServices.Factory.get();
}
@Bean @ConditionalOnMissingBean(KieBase.class) public KieBase kieBase() throws IOException { return kieContainer().getKieBase();
}
@Bean @ConditionalOnMissingBean(KieSession.class) public KieSession kieSession() throws IOException {
KieSession kieSession = kieContainer().newKieSession();
KieUtils.setKieSession(kieSession); return kieSession;
}
@Bean @ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class) public KModuleBeanFactoryPostProcessor kiePostProcessor() { return new KModuleBeanFactoryPostProcessor();
}
}
此类主要用来初始化Drools的配置,其中需要注意的是对KieContainer和KieSession的初始化之后都将其设置到KieUtils类中。
KieUtils
KieUtils类中存储了对应的静态方法和静态属性,供其他使用的地方获取和更新。
public class KieUtils {
private static KieContainer kieContainer;
private static KieSession kieSession;
public static KieContainer getKieContainer() { return kieContainer;
}
public static void setKieContainer(KieContainer kieContainer) {
KieUtils.kieContainer = kieContainer;
kieSession = kieContainer.newKieSession();
}
public static KieSession getKieSession() { return kieSession;
}
public static void setKieSession(KieSession kieSession) {
KieUtils.kieSession = kieSession;
}
}
ReloadDroolsRules
提供了reload规则的方法,也是本篇博客的重点之一,其中从数据库读取的规则代码直接用字符串代替,读者可自行进行替换为数据库操作。
@Service
public class ReloadDroolsRules {
public void reload() throws UnsupportedEncodingException {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
kfs.write("src/main/resources/rules/temp.drl", loadRules());
KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
Results results = kieBuilder.getResults(); if (results.hasMessages(Message.Level.ERROR)) {
System.out.println(results.getMessages()); throw new IllegalStateException("### errors ###");
}
KieUtils.setKieContainer(kieServices.newKieContainer(getKieServices().getRepository().getDefaultReleaseId()));
System.out.println("新规则重载成功");
}
private String loadRules() { // 从数据库加载的规则 return "package plausibcheck.adress/n/n import com.neo.drools.model.Address;/n import com.neo.drools.model.fact.AddressCheckResult;/n/n rule /"Postcode 6 numbers/"/n/n when/n then/n System.out.println(/"规则2中打印日志:校验通过!/");/n end";
}
private KieServices getKieServices() { return KieServices.Factory.get();
}
}
TestController
提供了验证入口和reload入口。
@RequestMapping("/test")
@Controller public class TestController {
@Resource private ReloadDroolsRules rules;
@ResponseBody @RequestMapping("/address") public void test(){
KieSession kieSession = KieUtils.getKieSession();
Address address = new Address();
address.setPostcode("994251");
AddressCheckResult result = new AddressCheckResult();
kieSession.insert(address);
kieSession.insert(result); int ruleFiredCount = kieSession.fireAllRules();
System.out.println("触发了" + ruleFiredCount + "条规则");
if(result.isPostCodeResult()){
System.out.println("规则校验通过");
}
}
@ResponseBody @RequestMapping("/reload") public String reload() throws IOException {
rules.reload(); return "ok";
}
}
其他
其他类和文件内容参考springboot集成部分或demo源代码。
操作步骤如下:启动项目访问http://localhost:8080/test/address 会首先触发默认加载的address.drl中的规则。当调用reload之后,再次调用次方法会发现触发的规则已经变成重新加载的规则了。
GitHub demo下载地址:https://github.com/secbr/drools/tree/master/springboot-drools-reload-rules
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/15198.html