在《Drools7.0.0.Final規(guī)則引擎教程》之Springboot集成中介紹了怎樣將Drools與Springboot進(jìn)行集成,本篇博客介紹一下集成之后,如何實現(xiàn)從數(shù)據(jù)庫讀取規(guī)則并重新加載規(guī)則的簡單demo。因本章重點介紹的是Drools相關(guān)操作的API,所以將查詢數(shù)據(jù)庫部分的操作省略,直接使用數(shù)據(jù)庫查詢出的規(guī)則代碼來進(jìn)行規(guī)則的重新加載。另外,此示例采用訪問一個http請求來進(jìn)行重新加載,根據(jù)實際需要可考慮定時任務(wù)進(jìn)行加載等擴展方式。最終的使用還是要結(jié)合具體業(yè)務(wù)場景來進(jìn)行分析擴展。
整體項目結(jié)構(gòu)
上圖是基于intellij maven的項目結(jié)構(gòu)。其中涉及到springboot的Drools集成配置類,重新加載規(guī)則類。一些實體類和工具類。下面會抽出比較重要的類進(jìn)行分析說明。
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();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
此類主要用來初始化Drools的配置,其中需要注意的是對KieContainer和KieSession的初始化之后都將其設(shè)置到KieUtils類中。
KieUtils
KieUtils類中存儲了對應(yīng)的靜態(tài)方法和靜態(tài)屬性,供其他使用的地方獲取和更新。
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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
ReloadDroolsRules
提供了reload規(guī)則的方法,也是本篇博客的重點之一,其中從數(shù)據(jù)庫讀取的規(guī)則代碼直接用字符串代替,讀者可自行進(jìn)行替換為數(shù)據(jù)庫操作。
@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("新規(guī)則重載成功");
}
private String loadRules() {
// 從數(shù)據(jù)庫加載的規(guī)則
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(\"規(guī)則2中打印日志:校驗通過!\");\n end";
}
private KieServices getKieServices() {
return KieServices.Factory.get();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
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("觸發(fā)了" + ruleFiredCount + "條規(guī)則");
if(result.isPostCodeResult()){
System.out.println("規(guī)則校驗通過");
}
}
@ResponseBody
@RequestMapping("/reload")
public String reload() throws IOException {
rules.reload();
return "ok";
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
其他
其他類和文件內(nèi)容參考springboot集成部分或demo源代碼。
操作步驟如下:啟動項目訪問http://localhost:8080/test/address 會首先觸發(fā)默認(rèn)加載的address.drl中的規(guī)則。當(dāng)調(diào)用reload之后,再次調(diào)用次方法會發(fā)現(xiàn)觸發(fā)的規(guī)則已經(jīng)變成重新加載的規(guī)則了。
CSDN demo下載地址:http://download.csdn.net/detail/wo541075754/9918297
GitHub demo下載地址:https://github.com/secbr/drools/tree/master/springboot-drools-reload-rules
后語
此系列課程持續(xù)更新中,QQ群:593177274(可掃描左上側(cè)欄目二維碼),歡迎大家加入討論。點擊鏈接關(guān)注《Drools博客專欄》。由于Drools資料較少,教程編寫不易,每篇博客都親身實踐編寫demo。如果對你有幫助也歡迎贊賞(微信)! 也是對原創(chuàng)的最大支持!