Drools是一個基於java的規則引擎,開源的,可以將復雜多變的規則從硬編碼中解放出來,以規則腳本的形式存放在文件中,使得規則的變更不需要修正代碼重啟機器就可以立即在線上環境生效。隨着互聯網金融的興起,個人信用資質的審核等業務如果采用硬編碼的方式,規則一旦變了,那么編碼也會改變,采用硬編碼的方式就不能適應規則的快速變化。
下面是我學習的springboot搭建的第一個規則引擎的例子,從網上學習的,感覺很好。鏈接《Drools7.0.0.Final規則引擎教程》之Springboot集成,編輯好的例子已經放到本人的GitHub上,可以下載運行。
測試類:TestController
@RequestMapping("/test")
@Controller
public class TestController {
@Resource
private KieSession kieSession;
@ResponseBody
@RequestMapping("/address")
public void test() {
Address address = new Address();
address.setPostcode("99425");
AddressCheckResult result = new AddressCheckResult();
FactHandle f = kieSession.insert(address);
FactHandle f1 = kieSession.insert(result);
int ruleFiredCount = kieSession.fireAllRules();
System.out.println("觸發了" + ruleFiredCount + "條規則");
if (result.isPostCodeResult()) {
System.out.println("規則校驗通過");
}
// kieSession.delete(f);
// kieSession.delete(f1);
// 這里添加過濾器
Address address1 = new Address();
address1.setPostcode("2017");
AddressCheckResult result1 = new AddressCheckResult();
kieSession.insert(address1);
kieSession.insert(result1);
AddressFilter addressFilter = new AddressFilter(address1);
int ruleFiredCount1 = kieSession.fireAllRules(addressFilter);
System.out.println("觸發了" + ruleFiredCount1 + "條規則");
}
}
springboot運行類:
@SpringBootApplication
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public class SpringbootDrools {
public static void main(String[] args) {
SpringApplication.run(SpringbootDrools.class, args);
}
}
實體類:
public class Address {
private String postcode;
private String street;
private String state;
}
public class AddressCheckResult {
private boolean postCodeResult = false; // true:通過校驗;false:未通過校驗
public boolean isPostCodeResult() {
return postCodeResult;
}
public void setPostCodeResult(boolean postCodeResult) {
this.postCodeResult = postCodeResult;
}
}
springboot自動配置的類,這個是與spring不同的地方,后面在springboot專題中專門講如何將spring的配置文件轉換到springboot
@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();
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 {
return kieContainer().newKieSession();
}
@Bean
@ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)
public KModuleBeanFactoryPostProcessor kiePostProcessor() {
return new KModuleBeanFactoryPostProcessor();
}
}
過濾器:自定義實現過濾某些規則。
public class AddressFilter implements AgendaFilter {
// 傳進來的是Address對象,把postcode以2017年開頭的執行規則,否則不執行
private final Address address;
public AddressFilter(Address address) {
this.address = address;
}
@Override
public boolean accept(Match match) {
return match.getRule().getName().contains(address.getPostcode());
}
}
運行結果:
規則中打印日志:校驗通過! 規則中打印日志:校驗通過2017! 觸發了2條規則 規則校驗通過 規則中打印日志:校驗通過2017! 觸發了1條規則
