Drools规则引擎入门指南(一)

最近项目需要增加风控系统,在经过一番调研以后决定使用Drools规则引擎。因为项目是基于SpringCloud的架构,所以此次学习使用了SpringBoot2.0版本结合Drools7.14.0.Final版本。

引入依赖

<dependency>    <groupId>org.drools</groupId>    <artifactId>drools-core</artifactId>    <version>7.14.0.Final</version></dependency><dependency>    <groupId>org.kie</groupId>    <artifactId>kie-spring</artifactId>    <version>7.14.0.Final</version></dependency>

创建配置类

@Configurationpublic 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());    }

    @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();        return kieSession;    }
    @Bean    @ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)    public KModuleBeanFactoryPostProcessor kiePostProcessor() {        return new KModuleBeanFactoryPostProcessor();    }    public KieServices getKieServices() {        System.setProperty("drools.dateformat","yyyy-MM-dd");        return KieServices.Factory.get();    }}

在这个时候我们的基本环境已经搭建好了,接下来我们一起来学习Drools吧

HelloWord

程序员的世界里,我们学习任何一门语言都是以HelloWord开启的,本次学习也不例外。

1.创建规则文件

Drools的规则文件是以*.drl结尾的文件,我们来看一个最简单的规则文件中都是包含什么。

通常来说,我们会把规则文件放在resources资源文件夹下,这里呢我们在resources文件夹下新建一个rules文件夹,然后再新建一个HelloWord.drl文件

package rules;import cn.org.zhixiang.entity.User;import java.lang.String;import java.util.List;
rule "hello,word"    when        eval(true)    then        System.err.println("hello,word!");end
  1. 规则文件,就是我们新建的这个HelloWord.drl可以理解为一个Java类
  2. package,这个跟Java中的包名是差不多的
  3. import,此文件中需要的类。
  4. rule,可以理解为给这个规则起的一个名字,一个规则文件中可以包含多个rule。
  5. when,when下面可以放置一些条件判断的表达式以及定义一些变量什么的。如果里面内容为空的话则会默认添加一个eval(true)代表一个为true的表达式
  6. then,当when下面的表达式为true是then下方的代码才会执行,在这里可以直接编写Java代码(代码所需要的类通过import引入),当然也可以使用when模块定义的一些变量
  7. end 代表规则hello,word的结束。

2.Java调用

现在我们的规则文件写好以后就可以在Java中来进行调用了。

1. 新建一个测试类DroolsApplicationHelloWordTests

@RunWith(SpringRunner.class)@SpringBootTestpublic class DroolsApplicationHelloWordTests {
    @Autowired    KieSession kieSession;
}

上方注入的kieSession对象就是以后与Drools打交道最常用的一个对象了,通过它可以直接操作在配置类kieFileSystem方法中加载的所有的规则文件

2. 编写测试代码

@Testpublic void testHelloWord() {    kieSession.fireAllRules();}

kieSession.fireAllRules方法是执行所有的规则,在运行了这个测试方法之后我们应该就可以看到控制台打印的一句hello,word!了

基础学习

1. 向规则文件传参

1. 在entity包下新增一个User的实体类

public class User {    private String name;    private int age;
    public User(String name, int age) {        this.name = name;        this.age = age;    }    //省略getter,setter}

2. 在hello,word规则下方再次新建一个规则user

rule "user"    when      $u:User(name=="张三",age==18)    then        $u.setName("李四");        System.err.println("hello,word:"+$u.getName());end

$u:User(name==“张三”,age==18)的意思就是当存在一个user对象,并且它的name属性等于张三age等于18时就把这个对象赋值给$u。

在下方的then模块,如果上方的条件成立时就把$u的name属性更新一下,然后打印。

3. 编写测试代码

@Testpublic void testUser() {    User user=new User("张三",18);    kieSession.insert(user);    kieSession.fireAllRules();    System.err.println("规则执行完毕后张三变为了:"+user.getName());}

我们可以使用kieSession.insert方法向规则文件中传参,然后在调用方法后你会发现在规则文件中更改的值在Java代码中也被更改了。

4. 存在的小问题

可能你会发现上方代码执行的时候连那句helloword也打印了,为什么呢,这是因为HelloWord那条规则没有验证条件再加上kieSession.fireAllRules()本来就是执行所有被加载的规则的。那么避免这种情况的办法就是执定本次执行的规则

@Test    public void testOneRule() {        User user=new User("张三",18);        kieSession.insert(user);        kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("user"));    }

上方的user就是指定的本次执行的规则名称了。

5.扩展操作

上方我们通过RuleNameEndsWithAgendaFilter对象成功指定了需要执行的规则文件,其实通过查看此对象的源码我们发现这个对象是AgendaFilter的一个实现类,决定执不执行一个规则的条件是accept方法返回的boolean值决定的。 所以说如果我们希望可以一次批量匹配多个规则的话可以通过继承AgendaFilter重写accept方法哦

2. 常用运算符

1. 连接符

Drools中存在的三种连接符,上方的代码中我们已经使用过一个了,那就$u:User(name==“张三”,age==18)中的逗号,这里的逗号其实就是and的意思。另外的两个运算符就是&&和||,相信它们两个的意思不用我来介绍了吧。

不过有一点需要注意的是&&和|| 和逗号,不能同时出现。要不你选择用&&和||要不就只用逗号, 。

2. 类型比较操作符

1.首先就是<,>,==,!=,>=,<=这六个

它们是配合eval使用的,比如上方我们使用的eval(true)就是直接返回的true。当我们比较常量时可以使用eval(u.age>b.age)

2. contains not contains

contains用于判断对象的某个字段是否包含另外一个对象

rule "contains"    when      $s:String()      $u:User(name contains $s)    then        System.err.println("用户张三存在");end
@Test    public void testContains() {       String name="张三";        User user=new User("张三",18);        kieSession.insert(name);        kieSession.insert(user);        kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("contains"));    }

not contains顾明思议就是不包含

3. memberOf not memberOf

memberOf用于判断对象的某个字段是否存在一个集合中

rule "memberOf"    when      $list:List()      $u:User(name memberOf $list)    then        System.err.println("用户李四存在");end
@Test    public void testMemberOf() {        List list=new ArrayList();        list.add("张三");        list.add("李四");        User user=new User("李四",18);        kieSession.insert(list);        kieSession.insert(user);        kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("memberOf"));    }

not memberOf顾明思议就是不存在

3. matches not matches

matches就是用于匹配正则表达式的了

rule "matches"    when      $u:User(name matches "张.*")    then        System.err.println("用户张xx存在");end
@Test   public void testMatches() {       User user=new User("张三",18);       kieSession.insert(user);       kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("matches"));   }

not matches不用我说了吧

本文分享自微信公众号 - Java学习录(Javaxuexilu)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励