https://www.bilibili.com/video/BV1nW421R7qJ 来自尚硅谷
背景
/**
* 设置订单积分
*/
public void setOrderPoint(Order order){
if (order.getAmout() <= 100){
order.setScore(0);
}else if(order.getAmout() > 100 && order.getAmout() <= 500){
order.setScore(100);
}else if(order.getAmout() > 500 && order.getAmout() <= 1000){
order.setScore(500);
}else{
order.setScore(1000);
}
}
对于不经常变化的业务,我们通常是将规则硬编码到程序中。但是经常变化的业务,我们就得把业务流程从代码中剥离出来。
1、硬编码实现业务规则难以维护
2、硬编码实现业务规则难以应对变化
3、业务规则发生变化需要修改代码,重启服务后才能生效
那么面对上面的业务场景,还有什么好的实现方式吗?
此时我们需要引入规则引擎来帮助我们将规则从代码中分离出去,让开发人员从规则的代码逻辑中解放出来,把规则的维护和设置交由业务人员去管理。
规则引擎概述
规则引擎,全称为业务规则管理系统,规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。
需要注意的是规则引擎并不是一个具体的技术框架,而是指的一类系统。目前市面上具体的规则引擎产品有:drools、VisualRules、iLog等。
规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台。
系统中引入规则引擎后,业务规则不再以程序代码的形式驻留在系统中,取而代之的是处理规则的规则引擎,业务规则存储在规则库中,完全独立于程序。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务规则等。业务规则被加载到规则引擎中供应用系统调用。
对于一些存在比较复杂的业务规则并且业务规则会频繁变动的系统比较适合使用规则引擎,如下:
1、风险控制系统----风险贷款、风险评估
2、反欺诈项目----银行贷款、征信验证
3、决策平台系统----财务计算
4、促销平台系统----满减、打折、加价购
Drools
drools是一款由JBoss组织提供的基于Java语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。
入门案例
引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>17</java.version>
<drools.version>8.41.0.Final</drools.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-mvel</artifactId>
<version>${drools.version}</version>
</dependency>
</dependencies>
添加Drools配置类 (固定的),规则文件所在路径一定要指定对
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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 规则引擎配置类
*/
@Configuration
public class DroolsConfig {
private static final KieServices kieServices = KieServices.Factory.get();
//制定规则文件的路径
private static final String RULES_CUSTOMER_RULES_DRL = "rules/order.drl";
@Bean
public KieContainer kieContainer() {
//获得Kie容器对象
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_CUSTOMER_RULES_DRL));
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
KieModule kieModule = kieBuilder.getKieModule();
KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
return kieContainer;
}
}
创建实体类Order
import lombok.Data;
@Data
public class Order {
private double amout;
private double score;
}
lombok指定好版本很重要
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
创建规则文件resources/rules/order.drl
//订单积分规则
package com.order
//规则一:100元以下 不加分
rule "order_rule_1"
when
$order:Order(amout < 100)
then
$order.setScore(0);
System.out.println("成功匹配到规则一:100元以下 不加分");
end
//规则二:100元 - 500元 加100分
rule "order_rule_2"
when
$order:Order(amout >= 100 && amout < 500)
then
$order.setScore(100);
System.out.println("成功匹配到规则二:100元 - 500元 加100分");
end
//规则三:500元 - 1000元 加500分
rule "order_rule_3"
when
$order:Order(amout >= 500 && amout < 1000)
then
$order.setScore(500);
System.out.println("成功匹配到规则三:500元 - 1000元 加500分");
end
//规则四:1000元以上 加1000分
rule "order_rule_4"
when
$order:Order(amout >= 1000)
then
$order.setScore(1000);
System.out.println("成功匹配到规则四:1000元以上 加1000分");
end
编写测试类
package com.atguigu.drools;
import org.junit.jupiter.api.Test;
import com.atguigu.drools.model.Order;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DroolsDemosApplicationTests {
@Autowired
private KieContainer kieContainer;
@Test
public void test(){
//从Kie容器对象中获取会话对象
KieSession session = kieContainer.newKieSession();
//Fact对象,事实对象
Order order = new Order();
order.setAmout(1300);
//将Order对象插入到工作内存中
session.insert(order);
//激活规则,由Drools框架自动进行规则匹配,如果规则匹配成功,则执行当前规则
session.fireAllRules();
//关闭会话
session.dispose();
System.out.println("订单金额:" + order.getAmout() +
",添加积分:" + order.getScore());
}
}
问:我们虽然没有在代码中编写规则的判断逻辑,但是我们还是在规则文件中编写了业务规则,这跟在代码中编写规则有什么本质的区别呢?
答案:使用规则引擎时业务规则可以做到动态管理。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务规则等。这样就可以做到在不重启服务的情况下调整业务规则。
drools规则引擎原理
drools规则引擎由以下三部分构成:
- Working Memory(工作内存)
- Rule Base(规则库)
- Inference Engine(推理引擎)
其中Inference Engine(推理引擎)又包括:
- Pattern Matcher(匹配器) 具体匹配哪一个规则,由这个完成
- Agenda(议程)
- Execution Engine(执行引擎)
相关概念:
-
Working Memory:工作内存,drools规则引擎会从Working Memory中获取数据并和规则文件中定义的规则进行模式匹配,所以我们开发的应用程序只需要将我们的数据插入到Working Memory中即可,例如本案例中我们调用kieSession.insert(order)就是将order对象插入到了工作内存中。
-
Fact:事实,是指在drools 规则应用当中,将一个普通的JavaBean插入到Working Memory后的对象就是Fact对象,例如本案例中的Order对象就属于Fact对象。Fact对象是我们的应用和规则引擎进行数据交互的桥梁或通道。
-
Rule Base:规则库,我们在规则文件中定义的规则都会被加载到规则库中。
-
Pattern Matcher:匹配器,将Rule Base中的所有规则与Working Memory中的Fact对象进行模式匹配,匹配成功的规则将被激活并放入Agenda(议程)中。
-
Agenda:议程,用于存放通过匹配器进行模式匹配后被激活的规则。
-
Execution Engine:执行引擎,执行Agenda中被激活的规则。
规则文件的编写什么的没有放,可以去看一看