原创

SpringBoot集成规则引擎Drools实例

SpringBoot集成规则引擎Drools实现消费赠送积分案例

1、第一步: 创建工程,引入jar

jar 依赖,注意,排除spring相关依赖
<!--规则引擎-->
<dependency>
  <groupId>org.kie</groupId>
  <artifactId>kie-spring</artifactId>
  <version>${drools.version}</version>
  <exclusions>
    <exclusion>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
    </exclusion>
  </exclusions>
</dependency>

2、创建 drools 自动配置类

drools 在spring 或者springboot中用法一样,其实就是创建好一些bean
package com.mashibing.drools.config;

import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

/*** <p> 规则引擎自动配置类 </p> * @author 狂奔程序猿 */
@Configuration
public class DroolsAutoConfiguration {
    private static final String RULES_PATH = "rules/";

    private KieServices getKieServices() {
        return KieServices.Factory.get();
    }

    @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(() -> kieRepository.getDefaultReleaseId());
        KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
        kieBuilder.buildAll();
        KieContainer kieContainer = getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
        return kieContainer;
    }

    @Bean
    @ConditionalOnMissingBean(KieBase.class)
    public KieBase kieBase() throws IOException {
        return kieContainer().getKieBase();
    }
}

3、订单实体类

@Data
@Accessors(chain = true)
public class Order {
    /*** 订单原价金额 */
    private int price;
    /***下单人 */
    private User user;
    /***积分 */
    private int score;
    /*** 下单日期 */
    private Date bookingDate;
}

4、规则引擎文件

package rules 
import com.mashibing.drools.entity.Order 

rule "zero" 
  no-loop true 
  lock-on-active true 
  salience 1 
  when
  $s : Order(amout <= 100) 
  then
    $s.setScore(0); 
    update($s); 
end 

rule "add100" 
  no-loop true 
  lock-on-active true 
  salience 1 
  when
    $s : Order(amout > 100 && amout <= 500) 
  then
    $s.setScore(100); 
    update($s); 
end 

rule "add500" 
  no-loop true 
  lock-on-active true 
  salience 1 
  when
    $s : Order(amout > 500 && amout <= 1000)
  then
    $s.setScore(500); 
    update($s); 
end 

rule "add1000" 
  no-loop true 
  lock-on-active true 
  salience 1 
  when
    $s : Order(amout > 1000) 
  then
    $s.setScore(1000);
    update($s); 
end

5、客户端

/*** 需求 * 计算额外积分金额 规则如下: 订单原价金额 * 100以下, 不加分 * 100-500 加100分 * 500-1000 加500分 * 1000 以上 加1000分 */
public class DroolsOrderTests extends DroolsApplicationTests {
    @Resource
    private KieContainer kieContainer;

    @Test
    public void Test() throws Exception {
        List<Order> orderList = getInitData();
        for (Order order : orderList) {
            if (order.getAmout() <= 100) {
                order.setScore(0);
                addScore(order);
            } else if (order.getAmout() > 100 && order.getAmout() <= 500) {
                order.setScore(100);
                addScore(order);
            } else if (order.getAmout() > 500 && order.getAmout() <= 1000) {
                order.setScore(500);
                addScore(order);
            } else {
                order.setScore(1000);
                addScore(order);
            }
        }
    }

    @Test
    public void droolsOrderTest() throws Exception {
        KieSession kieSession = kieContainer.newKieSession();
        List<Order> orderList = getInitData();
        for (Order order : orderList) {
            // 1-规则引擎处理逻辑 
            kieSession.insert(order);
            kieSession.fireAllRules();
            // 2-执行完规则后, 执行相关的逻辑
            addScore(order);
        }
        kieSession.dispose();
    }

    private static void addScore(Order o) {
        System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());
    }

    private static List<Order> getInitData() throws Exception {
        List<Order> orderList = new ArrayList<>();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        {
            Order order = new Order();
            order.setAmout(80);
            order.setBookingDate(df.parse("2015-07-01"));
            User user = new User();
            user.setLevel(1);
            user.setName("Name1");
            order.setUser(user);
            order.setScore(111);
            orderList.add(order);
        }
        {
            Order order = new Order();
            order.setAmout(200);
            order.setBookingDate(df.parse("2015-07-02"));
            User user = new User();
            user.setLevel(2);
            user.setName("Name2");
            order.setUser(user);
            orderList.add(order);
        }
        {
            Order order = new Order();
            order.setAmout(800);
            order.setBookingDate(df.parse("2015-07-03"));
            User user = new User();
            user.setLevel(3);
            user.setName("Name3");
            order.setUser(user);
            orderList.add(order);
        }
        {
            Order order = new Order();
            order.setAmout(1500);
            order.setBookingDate(df.parse("2015-07-04"));
            User user = new User();
            user.setLevel(4);
            user.setName("Name4");
            order.setUser(user);
            orderList.add(order);
        }
        return orderList;
    }
}

6、drools 开发小结

6.1 drools 组成 drools规则引擎由以下几部分构成:
Working Memory(工作内存)
Rules(规则库)
Facts
Production memory
Working memory
Agenda
如下图所示:


6.2 相关概念说明

Working Memory:工作内存,drools规则引擎会从Working Memory中获取数据并和规则文件中定义的规则进行模式匹配,所以我们开发的应用程序只需要将我们的数据插入到Working Memory中即可,例如本案例中我们调用kieSession.insert(order)就是将order对象插入到了工作内存中。
Fact:事实,是指在drools 规则应用当中,将一个普通的JavaBean插入到Working Memory后的对象就是Fact对象,例如本案例中Order对象就属于Fact对象。Fact对象是我们的应用和规则引擎进行数据交互的桥梁或通道。
Rules:规则库,我们在规则文件中定义的规则都会被加载到规则库中。
Pattern Matcher:匹配器,将Rule Base中的所有规则与Working Memory中的Fact对象进行模式匹配,匹配成功的规则将被激活并放入Agenda中。
Agenda:议程,用于存放通过匹配器进行模式匹配后被激活的规则。

6.3 规则引擎执行过程


6.4 KIE介绍

在上述分析积分兑换的过程中,简单地使用了 "kie "开头的一些类名,Kie全称为Knowledge Is Everything,即"知识就是一切"的缩写,是Jboss一系列项目的总称。官网描述:这个名字渗透在GitHub账户和Maven POMs中。随着范围的扩大和新项目的展开,KIE(Knowledge Is Everything的缩写)被选为新的组名。KIE的名字也被用于系统的共享方面;如统一的构建、部署和使用。


本文链接地址:http://www.ysxbohui.com/article/307

正文到此结束