引入规则引擎背景
现状
在目前的很多行业应用中,如银行、保险、互联网金融等领域,存在着大量的业务规则,这些业务规则有如下的特点:
业务规则数量繁多、非常复杂、且规则处于不断的更新变化中
现有系统的很多做法是将业务规则绑定在程序代码中。
存在的问题
当业务规则变更时,对应的代码也得更改,即使每次小的变更都需要经历开发、测试验证上线等过程,变更的成本比较大。
长时间系统变得越来越难以维护。
系统僵化,新需求插入困难。
新需求上线周期较长 。
什么是规则引擎
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
- 规则引擎的核心就是获取knowledge(知识)
- 应用knowledge到特定的数据上(fact)
- 使用 “production rules(产生式规则)” IF <conditions> THEN <actions> Rule表达逻辑(任何逻辑都可以用这种方式表达)
引入规则引擎好处
实现业务逻辑与业务规则的分离,实现业务规则的集中管理。
可以动态修改业务规则,从而快速响应需求变更。
使业务人员也可以参与编辑、维护系统的业务规则。
使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单。
- Rules技术提供了一种新的方式用于创建业务应用系统,通过“声明式”的rule语言写业务逻辑,而不是传统的程序语言
- Rule engine非常适合解决复杂问题,且在没有更好的其他
- Rule engine非常适合用来表述业务逻辑
什么是规则?
- 一个rule由conditions,和actions组成。当所有的conditions匹配,rule可能“fire” Conditions即LHS(left hand side)
- Actions即RHS(right hand side或者consequence)
- Rule操纵应用程序中的数据( fact )
术语:
- Rule engines(比如Drools)使用正向或者反向链(或者混合使用)
- 正向链从事实到结论的推理。rule在LHS conditions匹配的时候执行。Actions可以改变facts,并可能导致新rule被fire。
- 反向链指则是从假设,即要证明的结论,到事实的推理
推理引擎:
- 规则系统的大脑实际上就是一个推理引擎,用于匹配facts和rules
- 推理引擎将事实、数据与产生式规则进行匹配(模式匹配),以推出结论
- 当匹配被找到,rule actions被fire
- Actions—经常会改变facts的状态,或者在应用上执行一些“外部”action
正向链
正向链接是一个非常强大的概念,它使原子规则能够组合成规则集,而无需定义规则间的依赖性,甚至不必知道这些依赖性。但是,在某些情况下,规则编写者可能希望能够对链接行为提供更多控制,尤其是能够限制发生的链接。这使规则建模器能够做到以下几点:
- 限制规则的重复执行,从而避免得到不正确的结果。
- 提高性能。
- 防止出现失控循环。
工作原理
将用户编写的规则文件(*.drl) 通过工具类加载、编译、打成jar包后,加入到指定的地方(一般是和规则引擎打交道的会话session )供规则引擎去调用和执行。
实例准备:
添加pom依赖
<!--规则引擎 drools-->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>5.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>5.5.0.Final</version>
</dependency>
编写实体类
public class Customer {
//姓名
private String name;
//年龄
private int age;
//性别
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
编写规则文件(*.drl)
import Customer;//导入实体类,导入写法与Java文件相同
rule "one" //规则名称,不可出现重复规则名 属性块no-loop true //执行一次后,是否能被再次激活salience 1 //优先级别
when //条件块
#eval(true); //匹配结果
$customer:Customer(age > 30);
then //结果块
System.out.println("age>30岁的人:"+ $customer.getName());
end
rule
"second"no-loop true //执行一次后,是否能被再次激活salience 2 //优先级别
when
$customer:Customer(sex == "男",age > 25);
then
System.out.println("性别为男性且年龄大于25岁的人:"+ $customer.getName());
end
编写Java测试类
//drl文件路径
String filePath = "test.drl";
//读取drl文件路径
final Reader source = new FileReader(filePath);
final PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl(source);
if (builder.hasErrors()) {
System.out.println("规则脚本存在错误:" + builder.getErrors().toString()); } //注意这的package不是JDK中lang包下的package而是drools中的
final Package pkg = builder.getPackage(); //初始化规则库
final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
Package[] packages = ruleBase.getPackages();
for (Package p : packages) {
ruleBase.removePackage(p.getName());
} ruleBase.addPackage(pkg);
final StatefulSession session = ruleBase.newStatefulSession();
//实体类调用写法
Customer customer = new Customer("项羽",31,"男");
session.insert(customer); //调用drl文件中的rule进行判断并返回结果
session.fireAllRules(new AgendaFilter() {
public boolean accept(Activation activation) {
return !activation.getRule().getName().contains("_test");
}
}
);
//进行规则处理并进行结果返回
session.dispose();