Drools-決策表使用2-整合springboot
阿新 • • 發佈:2020-09-10
之前快速使用了決策表,本次接著整合springboot。
論大象裝冰箱需要幾步
- 建springboot-maven工程、新增pom、配置application.yml,新增boot啟動類。
- 將上篇demo的核心類,IOC到springboot中
- 新增測試controller,執行時可以通過REST介面觸發規則重新整理動作
新建springboot工程
- pom
<drools.version>7.42.0.Final</drools.version> <springboot.version>2.2.5.RELEASE</springboot.version> <dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>drools-decisiontables</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies>
- application.yml
server: port: 8000 spring: application: name: @project.artifactId@ profiles: active: local thymeleaf: cache: false app: drools: # 配置Drools決策表文件路徑,可多個 xlsFilePaths: - D:/temp/person_check.xls
- 啟動類
@SpringBootApplication public class BootDrools { public static void main(String[] args) { System.setProperty("drools.dateformat","yyyy-MM-dd"); SpringApplication.run(BootDrools.class, args); } }
核心整合點
Kie相關類的IOC化 -> KieUtilService
KieHelper
私有單例化,只有首次啟動和規則重刷時才發生變更- 提供規則觸發方法
- 提供規則重刷方法
- application.yml 配置的檔案路徑注入
- 程式碼:
@Service @ConfigurationProperties(prefix = "app.drools") @Slf4j public class KieUtilService { // @Autowired // private DroolsRuleService droolsRuleService; private List<String> xlsFilePaths = new ArrayList<>(); private KieHelper kieHelper; private final SpreadsheetCompiler compiler = new SpreadsheetCompiler(); @PostConstruct public void init() { reload(); }
注意KieSession
- 注意
KieHepler
、KieContainer
、KieBase
和KieSession
的關係 - 本次做法沒有考慮是否有狀態Session,直接使用方法/執行緒級Session,一個觸發動作就是一個新的Session
- 程式碼:
/** * 觸發規則 * @param fact */ public void fire(Object fact) { this.fire(fact, new FireOption().setFireLimit(-1)); } /** * 觸發規則,指定觸發配置 * @param fact * @param fireLimit */ public void fire(Object fact, FireOption option) { log.info(">> fire, fact:{}, option:{}", fact, option); KieSession session = kieHelper.build().newKieSession(); //Drools全域性變數 if(CollUtil.isNotEmpty(option.getGlobalVariables())) { for(Entry<String, Object> entry: option.getGlobalVariables().entrySet()) { session.setGlobal(entry.getKey(), entry.getValue()); } } //fact放入工作內容 session.insert(fact); //指定聚焦議程組 if(StrUtil.isNotBlank(option.getAgendaGroup())) { session.getAgenda().getAgendaGroup(option.getAgendaGroup()).setFocus(); } //觸發數量配置 int fireLimit = option.getFireLimit()==null ? -1 : option.getFireLimit(); int count = session.fireAllRules(fireLimit); log.info("本次觸發的規則數:{}", count); session.dispose(); //方法級KieSession log.info("<< fire, fact:{}", fact); }
規則過載
- 重新生成
KieHepler
例項 - 載入指定路徑的決策表文件
- 過載方法:
/** * 重新載入外接的決策表EXCEL規則檔案 */ public void reload() { log.info(">> reload"); log.info("配置的xls規則檔案列表:{}", xlsFilePaths.toString()); // 載入規則 this.kieHelper = null; KieHelper newKieHelper = new KieHelper(); try { for (String path : xlsFilePaths) { InputStream is = new FileInputStream(new File(path)); String drl = compiler.compile(is, InputType.XLS); log.info("{} to compile drl:\n{}", path, drl); newKieHelper.addContent(drl, ResourceType.DRL); } // 測試任意drl來源,測試通過 // List<DroolsRule> listAll = droolsRuleService.listAll(); // listAll.forEach(o -> newKieHelper.addContent(o.getDrlContent(), ResourceType.DRL)); } catch (FileNotFoundException e) { log.error("檔案讀取異常", e); throw new RuntimeException("檔案讀取異常", e); } // drl文字語法校驗 verifyDrl(newKieHelper); this.kieHelper = newKieHelper; log.info("<< reload"); }
- 測試controller:
@RestController public class TestCtrller { @Value("${spring.application.name}") private String app_name; @Autowired private KieUtilService kieUtilService; // @Autowired // private AppDroolsYmlConfigBean ymlBean; @GetMapping("/hello") public Object hello() { return app_name + "@" + LocalDateTime.now().toString(); } @GetMapping("/rule/fire") public Object ruleFire(PersonInfoEntity entity) { kieUtilService.fire(entity); // kieUtilService.fire(entity, new FireOption().setAgendaGroup("sign")); return entity; } @GetMapping("/rule/reload") public Object ruleReload() { kieUtilService.reload(); return "OK"; } }
小結
- 可以看出,本次demo並沒有採用網上主流的kie-spring整合方案,而是使用最少依賴結合IOC的方式。
PS:主流的Drools整合Spring、Spring-Web以及SpringBoot的demo都可以在下方demo原始碼同級目錄中找到。 - 單節點的整合相對還是簡單的,效能上咱也做不了太多改善了。但是多節點叢集下,比如Feign的負載均衡,只會過載某個節點,這是個問題。
- 叢集下過載規則解決方案
- MQ廣播
- Nacos監聽(下篇預告)