1. 问题引出

现有一个在线申请信用卡的业务场景,用户需要录入个人信息,如下图所示:
image.png

通过上图可以看到,用户录入的个人信息包括姓名,性别,年龄,学历,电话,所在公司,职位,月收入,是否有房,是否有车,是否有信用卡等。录入完成后店家申请按钮提交即可。

用户挍申请后,需要在系统服务端进行用户信息合法性检查(是否有资格申请信用卡),只有通过合法性检查的用的才可以成功申请到信用卡(注意:不同用户有可能申请到信用卡额度不同)。

检查用户信息合法性的规则如下:

规则编号 名称 **
1 检查学历与薪水1 如果申请人既没房也没车,同时学历为大专以下,并且月薪少于5000,那么不通过
2 检查学历与薪水2 如果申请人既没房也没车,同时学历为大专以下,并且月薪少于3000,那么不通过
3 检查学历与薪水3 如果申请人既没房也没车,同时学历为本科以上,并且月薪少于2000,同时之前没有信用卡的,那么不通过
4 检查申请人已有的信用卡数量 如果申请人现有的信用卡数量大于10,那么不通过

用户信息合法性检查通过后,还需要根据如下信用卡发放规则确认用户所办信用卡的额度。

规则编号 名称 **
1 规则1 如果申请人有房有车,或者月收入在20000以上,那么发放信用卡的额度为15000
2 规则2 如果申请人没房没车,但者月收入在10000~20000之间,那么发放信用卡的额度为6000
3 规则3 如果申请人没房没车,月收入在10000以下,那么发放信用卡的额度为3000
4 规则4 如果申请人有房没车或者没房但有车,月收入在10000以下,那么发放信用卡的额度为5000
5 规则5 如果申请人有房没车或者没房但有车,月收入在10000~20000之间,那么发放信用卡的额度为8000

思考:如果实现上面的业务逻辑呢?

我们最容易想到的就是使用分支判断(if - else) 实现,例如通过如下代码来检查用户信息合法性:

  1. //此处未伪代码
  2. //检查用户信息合法性。返回true表示检查通过,返回false表示检查不通过
  3. public boolean checkUser(User user){
  4. //如果申请人既没房也没车,同时学历为大专以下,并且月薪少于5000,那么不通过
  5. if(user.getHouse() == null
  6. && user.getCar() == null
  7. && user.getEducation().equals("大专以下")
  8. && user.getSalary() < 5000){
  9. return false;
  10. }
  11. //如果申请人既没房也没车,同时学历为大专以下,并且月薪少于3000,那么不通过
  12. if(user.getHouse() == null
  13. && user.getCar() == null
  14. && user.getEducation().equals("大专或本科")
  15. && user.getSalary() < 3000){
  16. return false;
  17. }
  18. ....各种情况....
  19. return true;
  20. }

如果用户信息合法性检查通过之后,还需要通过如下代码确定用户所办信用卡的额度:

  1. //根据用户输入信息确定信用卡额度
  2. public Integer determineCreditCardLimit(User user){
  3. //如果申请人有房有车,或者月收入在20000以上,那么发放信用卡的额度为15000
  4. if(user.getHouse() != null
  5. && user.getCar() != null
  6. || user.getSalary() > 2000){
  7. return 15000;
  8. }
  9. //如果申请人没房没车,但者月收入在10000~20000之间,那么发放信用卡的额度为6000
  10. else if(user.getHouse() == null
  11. && user.getCar() == null
  12. || user.getSalary() < 10000){
  13. return 3000;
  14. }
  15. ....各种情况....
  16. }

通过上面的伪代码我们可以看到,我们得到业务规则是通过Java代码实现的。这种实现方式存在如下问题:
1、硬编码实现业务规则难以维护
2、硬编码实现业务规则难以应对变化
3、业务规则发生变化需要修改代码,重启服务后才能生效。

那么面对上面的业务场景,还有什么好的实现方式吗?

答案是:规则引擎

2.规则引擎概述

2.1 什么是规则引擎

规则引擎,全称为业务规则管理系统,英文名为 BRMS(即 Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。

需要注意的是规则引擎并不是一个具体的技术框架,而是指的一类系统,即业务规则管理系统。目前市面上具体的规则引擎产品有:Drools、VisualRules、iLog 等。

规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台

上面的申请信用卡业务场景使用规则引擎后效果如下:
image.png

系统中引入规则引擎后,业务规则不再以程序代码的形式驻留在系统中,取而代之的是处理规则的规则引擎,业务规则存储在规则库中,完全独立于程序。业务独立于程序。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务规则等。业务规则被加载到规则引擎中供应用系统调用。

2.2 使用规则引擎的优势

使用规则引擎的优势如下:
1、业务规则与系统代码分离,实现业务规则的集中管理
2、在不重启服务的情况下可随时对业务规则进行扩展和维护
3、可以动态修改业务规则,从而快速响应需求变更
4、规则引擎是相对独立的,只关心业务规则,使得业务分析人员也可以参与编辑、维护系统的业务规则
5、减少了硬编码业务规则的成本和风险
6、使用规则引擎提供的规则编辑工具,使复杂业务规则实现变的简单

2.3 规则引擎应用场景

对于一些存在比较负责的业务规则并且业务规则会频繁变动的系统比较适合使用规则引擎,如下:
1、风险控制系统—— 风险贷款,风险评估
2、反欺诈项目—— 银行贷款,征信验证
3、决策平台系统 —— 财务计算
4、促销平台系统—— 满减、打折、加价购

2.4 Drools介绍

Drools是一款JBoss组织提供的基于Java语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。

Drools 官网: https://www.drools.org/
Drools源代码下载地址:

在项目中使用Drools的时候,即可以单独使用也可以整合spring使用。依赖如下:

  1. <!-- https://mvnrepository.com/artifact/org.drools/drools-compiler -->
  2. <dependency>
  3. <groupId>org.drools</groupId>
  4. <artifactId>drools-compiler</artifactId>
  5. <version>7.61.0.Final</version>
  6. </dependency>

如果我们使用IDEA 开发Drools应用,IDEA已经集成了Drools插件。如果使用eclipse开发Drools应用还需要单独安装Drools超级爱你。

Drools API开发步骤如下:
image.png

3.Drools入门案列

本小节通过一个Drools入门案例来让大家初步了解Drools的使用方式,对Drools有一个整体概念。

3.1 业务场景说明

业务场景:消费者在图书商城购买图书,下单后需要在支付页面显示订单优惠后的价格。具体规则如下:

规则编号 规则名称 描述
1 规则一 所购图书总价在100元以下的没有优惠
2 规则二 所购图书总价在100元到200元的优惠20元
3 规则三 所购图书总价在200元到300元的优惠50元
4 规则四 所购图书总价在300元以上的优惠100元

现在需要根据上面的规则计算优惠后的价格。

3.2 开发实现

第一步:创建maven 工程 drools_quickstart 并导入drools相关maven坐标。

https://www.bilibili.com/video/BV1Pa4y1a7u6?p=9&spm_id_from=pageDriver

3.3 小节

3.3.1 规则引擎构成

3.3.2 相关概念说明

3.3.3 规则执行过程

3.3.4 KIE介绍

4.Drools基础语法

5.规则属性

6.Drools高级语法

7.Sping整合Drools

8.workBench