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条规则