规则引擎技术解决方案
1 概述
1.1 规则引擎的背景
业务系统在应用过程中,常常包含着要处理“复杂、多变”的部分,这部分往往是“业务规则”或者是“数据的处理逻辑”。因此这部分的动态规则的问题,往往需要可配置,并对系统性能和热部署有一定的要求。从开发与业务的视角主要突出以下的一些问题:
1.1.1从开发人员视角来看
1)逻辑复杂,要使用大量if-else、switch-case来实现,或者使用设计模式。 但过于复杂的规则逻辑,使用设计模式也往往是存在大量并且关系复杂 的类,导致代码难于维护。
2)变更时需要从头梳理逻辑,在适当的地方进行if…else…、switch-case代码 逻辑调整,耗费大量时间进行梳理。
3)开发周期较长,当需求发生变更时,需要研发人员安排开发周期上线, 对于当下快速变化的业务,传统的开发工作方式显得捉襟见肘。
1.1.2从业务人员视角来看
1)业务人员期望友好的管理界面,不需要专业的开发技能就能够完成规则 的管理、发布。
2)期望能够实现热部署,由业务人员配置好之后即配即用。
3)减少业务规则对开发人员的依赖。
4)降低需求变动的时间成本,快速验证发布。
1.2 规则引擎介绍
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
规则本质上是一个函数,如y=f(x1,x2,….xn)。
规则引擎有三部分:
- 事实(Fact):就是用户驶入的已经事实,即已知对象。
- LHS(Left Hand Side):规则执行需要满足的条件。
- RHS(Right Hand Sike):规则执行后的返回对象。
两个重要模块:
- 规则管理:主要涉及规则、实施对象和规则集三个实体。涉及到规则变更时,最好对规则加版本,可通过规则版本控制,可以平滑灰度地改变规则,也便于测试规则的正确性。
- 规则执行:通过规则库数据,通过规则引擎的规则解析、规则编译,将可执行代码缓存起来。也可根据需求,不依赖规则库的存储方式,如选用Drools等第三方引擎,甚至基于ANTLR定制。
1.3 规则引擎使用场景
◆ 使用规则引擎的好处
■ 声明式编程:规则引擎允许你描述做什么而不是如何去做
■ 业务规则与系统代码分离,实现业务规则的集中管理。数据保存在系统对象中,逻辑保存在规则中。
■ 速度及可测量性:Rete算法、Leaps算法,以及由此衍生出来的Drools的Rete、Leaps算法,提供了对系统数据对象非常有效率的匹配
■ 知识集中化:通过使用规则,将建立一个可执行的规则库。这意味着规则库代表着现实中的业务策略的唯一对应,理想情况下可读性高的规则还可以被当作文档使用
■ 工具集成:例如Eclipse(将来可能在基于Web的界面上)这样的工具为规则的修改与管理、即时获得反馈、内容验证与修补提供了办法。审查与调试工具同样也可用了
■ 解释机制:通过将规则引擎的决断与决断的原因一起记录下来,规则系统提供了很好的“解释机制”
■ 易懂的规则:通过建立对象模型以及DSL(域定义语言),可以用接近自然语言的方式来编写规则。规则引擎是相对独立的,只关心业务规则,使得业务分析⼈员、非技术人员与领域专家也可以用他们自己的逻辑来理解规则,参与编辑、维护系统的业务规则
■ 在不重启服务的情况下可随时对业务规则进行扩展和维护
■ 可以动态修改业务规则,从⽽快速响应需求变更
■ 减少了硬编码业务规则的成本和风险
■ 使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单
◆ 适合使用规则引擎系统的场景
■ 用传统的代码开发比较复杂、繁琐
■ 问题虽然不复杂,但是用传统的代码开发比较脆弱,也就是经常修改
■ 没有优雅的算法
■ 业务规则频繁改变
■ 有很多业务专家
如:
- 风险控制系统----风险贷款、风险评估
- 反欺诈项目----银行贷款、征信验证
- 决策平台系统----财务计算
- 促销平台系统----满减、打折、加价购
- 手机运营商资费套餐
- 超市、商场,商城等等积分计算规则
- 寿险车险理赔
- 工资计算(ScriptEngine)
- 决策平台系统----业务决策判断
- PS:如果应用的生命周期很短,也没有必要使用Drools,使用规则引擎将会在中长期维护中得到好处。
◆ 不适合使用规则引擎系统的场景
虽然规则系统看起来比较不错,但是并不是任何地方都可以使用规则系统。
■ 很多简单、固定的业务系统,可以不用使用规则系统
■ 问题虽然不复杂,但是用传统的代码开发比较脆弱,也就是经常修改
■ 没有优雅的算法
■ 业务规则频繁改变
■ 开发时间紧、任务急、工作量大
2 总体设计方案
暂无。
3 规则引擎技术选型
对比内容 | Drools | easyRules | QlExpress | Apache Camel |
项目背景 | JBoss | 阿里 | Apache | |
SpringBoot整合 | V | V | 支持Spring | 支持Spring |
平台支持 | Java | Java | Java | Java |
热更新 | V | X | X | / |
维护 | 一般 | 难 | 难 | / |
LHS规则条件 | V | V | V | / |
RHSthen部分触发执行、业务处理 | V | V | V | / |
活跃度 | 非常活跃的社区支持;star 4.6k/last update 2023.8.2/commits 16898 | star 4.5k/last update 2020.12.7/commits 659 | star 4.2k/last update 2023.2.6/commits 309 | star 4.9k/last update aways/commits 309 |
性能 | 差 | 良好 | 高性能 | / |
学习成本 | 引擎设计和实现都比较复杂,学习成本高,适用于大型应用系统 | 方便且适用于Java的抽象的业务模型规则,轻量级类库和容易上手 | 需要一定的学习成本 | 需要一定的学习成本 |
免费开源 | V | V | V | V |
复杂业务场景的支持 | 复杂规则支持 | 简单规则。基于MVEL表达式的编程模型(适用于极简单的规则,一般不推荐) | 复杂规则支持 | / |
技术成熟度 | 高 | 一般 | 一般 | 高 |
规则引擎类型 | 业务规则引擎 | 业务规则引擎 | 业务规则引擎,表达式 | 路由和中介规则引擎。适用于集成/传输层。在系统之间映射消息格式,转换协议(JMS,HTTP,FTP等)和消息标准(如XML,JSON等)以及路由 |
3.1目前业务特点选型
法律法规业务规则、表达式(布尔组合)、语义语法分析等强业务需求,由业务人员将历年法律法规规则按照规则编写xml文档,由后端读取XML规则内容,通过对法律案例进行分词、匹配、正则表达式、语义关联分析等与读取的XML规则内容比对、匹配,实现对法律案例的关键字的提取,从而获取相应的结果。根据实际情况,先采用硬编码读取XML文件进行对text内容比对、匹配等方式完成任务。后期通过分享Drools、easyRule的方式实现业务和技术的分离,争取考虑使用页面配置规则存库、读取规则、匹配规则方式,形成公司自有的规则库。
4.Drools简介及使用
Drools是⼀款由JBoss组织提供的基于Java语⾔开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在⽂件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、不⽤重启服务器就可以在线上环境立即生效。
Drools官网地址:https://drools.org/
drools源码下载地址:https://github.com/kiegroup/drools
使用 Drools 需要将原有的代码抽象成:Rule(规则) + Fact(事实)。
在Java应用中使用Drools 规则引擎的步骤如下:
1.准备规则:创建规则文件并定义规则。
2.构建Kie容器:使用KieServices接口创建Kie容器。
3.获取KieBase:使用KieServices.newKieClasspathContainer()方法获取KieBase。
4.创建KieSession:使用KieBase.newKieSession)方法创建KieSession。
5.插入数据:使用KieSession.insert()方法插入数据。
6.执行规则:使用KieSession.fireAllRules()方法执行规则。
7.关闭KieSession:使用KieSession.dispose()方法关闭KieSession。
4.1 pom导包
<dependency><groupId>org.drools</groupId><artifactId>drools-core</artifactId><version>7.57.0.Final</version>
</dependency>
<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.57.0.Final</version>
</dependency>
<dependency><groupId>org.kie</groupId><artifactId>kie-api</artifactId><version>7.57.0.Final</version>
</dependency>
<dependency><groupId>org.drools</groupId><artifactId>drools-mvel</artifactId><version>7.57.0.Final</version>
</dependency>
Idea安装Drools插件。
4.2 resource下新建META-INF文件夹,新建并编写kmodule.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"><!--name:指定kbase 名称,可以是任意但必须唯一packages:指定规则文件存放目录,依据实际情况进行填写default:指定当前的kbase 是否为默认--><kbase name="rules" packages="rules" default="true"><!--name:指定ksession名称,可以是任意但必须唯一default:指定ksession 是否为默认--><ksession name="ksession-rules" default="true"/><!--<ksession name="name-rules" default="true"/>--></kbase>
</kmodule>
4.3 resource下新建rules文件夹,新建并编写crime-rules.drl文件
package rules;import com.example.testdemo.Judge;rule "crime_1"
when$judge:Judge(crime.contains("猥亵"));
then$judge.setSentence(3);System.out.println("触发猥亵,3个月");
endrule "crime_2" extends "crime_1"
whenJudge(crime.contains("抢劫"));
then$judge.setSentence(24);System.out.println("触发猥亵和抢劫, 2年");
endrule "crime_3" extends "crime_2"
whenJudge(crime.contains("杀人未遂"));
then$judge.setSentence(120);System.out.println("触发猥亵、抢劫、杀人未遂, 10年");
end
4.4 编写测试用例
/*** @author jingyan* @createTime 2019年07月04日 13:51:00* @Description*/
public class TestDrools {@Testpublic void test1() {// 第一步KieServices kieServices = KieServices.Factory.get();// 第二步KieContainer kieContainer = kieServices.getKieClasspathContainer();// 第三步KieSession kieSession = kieContainer.newKieSession("ksession-rules");// 业务对象Judge judge = new Judge();judge.setCrime("嫌疑人xxx,于2012年因猥亵、抢劫、杀人未遂,数案并罚");// 第四步kieSession.insert(judge);// 第五步:执行规则引擎kieSession.fireAllRules();// 第六步:关闭sessionkieSession.dispose();System.out.println("指定规则引擎后的结果:" + judge.getSentence());}
}
运行结果:
14:52:07.483 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: rules
14:52:07.535 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发猥亵,3个月
触发猥亵和抢劫, 2年
触发猥亵、抢劫、杀人未遂, 10年
14:52:07.571 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
14:52:07.571 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
14:52:07.571 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED
指定规则引擎后的结果:120
4.5Drools数据库表结构设计
-- ----------------------------
-- Table structure for drools_biz_rule
-- ----------------------------
DROP TABLE IF EXISTS `drools_biz_rule`;
CREATE TABLE `drools_biz_rule` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',`rule_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '规则标识',`rule_condition` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '规则数据',PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `uni_code`(`rule_code`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
5.EasyRule简介及使用
easy-rules是一款轻量级的java规则引擎。支持快速简单的从yml、json文件中加载Rule描述文件。EasyRule是Drools的简化版,裁剪了部分使用场景非常少的复杂功能,也简化了很多Drools中的组件。
官网:https://github.com/j-easy/easy-rules/
5.1框架特点
- 轻量级类库
- 容易学习的API
- 基于POJO的注解编程模型开发
- 通过高效的抽象来定义业务规则并易于用JAVA应用它们
- 支持通过原始规则创建复合规则
- 支持用表达式语言定义规则
5.2功能组件
- 事实(Fact):业务数据,结构类似HashMap;
- 规则(Rule):业务规则,包含条件评估、动作执行,条件评估结果为true,则执行对应动作;
- 规则引擎(Rule Engine):以指定的方式执行规则;
- 规则监听(Rule Listener):监听规则的执行情况;
- 规则引擎监听(Rule Engine Listener):监听规则引擎的执行情况。
5.3EasyRule使用
5.3.1 pom导包
<dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-core</artifactId><version>4.1.0</version>
</dependency>
<dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-support</artifactId><version>4.1.0</version>
</dependency>
<dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-mvel</artifactId><version>4.1.0</version>
</dependency>
5.3.2 resource下新建easyrules文件夹,新建并编写rule.yml文件
---
name: "crime_1"
description: "猥亵罪"
#priority: 1
condition: "judge.crime.contains(\"猥亵\")"
actions:- "judge.setSentence(3)"- "System.out.println(\"触发猥亵,3个月\")"---
name: "crime_2"
description: "猥亵和抢劫罪并罚"
#priority: 2
condition: "judge.crime.contains(\"猥亵\")&&judge.crime.contains(\"抢劫\")"
actions:- "judge.setSentence(24)"- "System.out.println(\"触发猥亵和抢劫, 2年\")"---
name: "crime_3"
description: "猥亵、抢劫罪和杀人未遂并罚"
#priority: 0
condition: "judge.crime.contains(\"猥亵\")&&judge.crime.contains(\"抢劫\")&&judge.crime.contains(\"杀人未遂\")"
actions:- "judge.setSentence(120)"- "System.out.println(\"触发猥亵、抢劫、杀人未遂, 10年\")"
5.3.3.4 编写测试用例
/*** @author jingyan* @createTime 2019年07月04日 15:54:00* @Description*/
public class TestEasyRule {@Testpublic void test() throws Exception {// 创建规则引擎RulesEngineParameters parameters = new RulesEngineParameters()//优先级超过定义的阈值,则跳过下一个规则//.priorityThreshold(10)//规则被触发时跳过后面的规则.skipOnFirstAppliedRule(false)//规则失败时跳过后面的规则.skipOnFirstFailedRule(true)//一个规则不会被触发跳过后面的规则.skipOnFirstNonTriggeredRule(false);RulesEngine engine = new DefaultRulesEngine(parameters);// 创建规则String filePath = System.getProperty("user.dir") + "/src/main/resources/easyrules/rule.yml";MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());Rules yamlRules = ruleFactory.createRules(new FileReader(filePath));Judge judge = new Judge();judge.setCrime("嫌疑人xxx,于2012年因猥亵、抢劫、杀人未遂,数案并罚");// 执行规则Facts facts = new Facts();facts.put("judge", judge);engine.fire(yamlRules, facts);System.out.println("指定规则引擎后的结果:" + JSON.toJSONString(judge));}
}
运行结果:
17:12:28.204 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact{name='judge', value=Judge(crime=嫌疑人xxx,于2012年因猥亵、抢劫、杀人未遂,数案并罚, sentence=0)}
17:12:28.204 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
17:12:28.229 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'crime_1' triggered
触发猥亵,3个月
17:12:28.232 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'crime_1' performed successfully
17:12:28.233 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'crime_2' triggered
触发猥亵和抢劫, 2年
17:12:28.233 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'crime_2' performed successfully
17:12:28.234 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'crime_3' triggered
触发猥亵、抢劫、杀人未遂, 10年
17:12:28.234 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'crime_3' performed successfully
指定规则引擎后的结果:{"crime":"嫌疑人xxx,于2012年因猥亵、抢劫、杀人未遂,数案并罚","sentence":120}
5.3.3.5EasyRule数据库表结构设计
-- ----------------------------
-- Table structure for easy_biz_rule
-- ----------------------------
DROP TABLE IF EXISTS `easy_biz_rule`;
CREATE TABLE `easy_biz_rule` (`id` bigint(22) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '规则名称',`description` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则描述',`priority` int(11) DEFAULT NULL COMMENT '权重',`composite_type` tinyint(4) DEFAULT NULL COMMENT '组合类型 1-and 2-or 3-all',`state` tinyint(4) DEFAULT NULL COMMENT '数据状态 0-有效 1-无效',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_name` (`name`) USING BTREE COMMENT '策略名称'
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;-- ----------------------------
-- Table structure for easy_biz_compose
-- ----------------------------
DROP TABLE IF EXISTS `easy_biz_compose`;
CREATE TABLE `easy_biz_compose` (`id` bigint(22) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`rule_id` bigint(22) NOT NULL COMMENT '规则ID',`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则名称',`description` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则描述',`condition` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则条件',`actions` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '执行动作',`priority` int(11) DEFAULT NULL COMMENT '规则权重',`state` tinyint(4) DEFAULT NULL COMMENT '数据状态 0-有效 1-无效',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_rule` (`rule_id`) USING BTREE COMMENT '规则'
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
6.QLExpress简介和使用
由阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。让业务人员就可以定义业务规则。支持标准的JAVA语法,还可以支持自定义操作符号、操作符号重载、函数定义、宏定义、数据延迟加载等。
QLExpress脚本引擎被广泛应用在阿里的电商业务场景,具有以下的一些特性:
- 1、线程安全,引擎运算过程中的产生的临时变量都是threadlocal类型。
- 2、高效执行,比较耗时的脚本编译过程可以缓存在本地机器,运行时的临时变量创建采用了缓冲池的技术,和groovy性能相当。
- 3、弱类型脚本语言,和groovy,javascript语法类似,虽然比强类型脚本语言要慢一些,但是使业务的灵活度大大增强。
- 4、安全控制,可以通过设置相关运行参数,预防死循环、高危系统api调用等情况。
- 5、代码精简,依赖最小,250k的jar包适合所有java的运行环境,在android系统的低端pos机也得到广泛运用。
官网:https://github.com/alibaba/QLExpress
6.1 pom导包
<dependency><groupId>com.alibaba</groupId><artifactId>QLExpress</artifactId><version>3.3.1</version>
</dependency>
6.2编写测试用例
/*** @author jingyan* @createTime 2023年08月04日 18:04:00* @Description 补充QLExpress表达式规则引擎*/
public class TestQLExpress {@Testpublic void test() throws Exception {ExpressRunner runner = new ExpressRunner();DefaultContext<String, Object> context = new DefaultContext<>();context.put("a", 1);context.put("b", 2);context.put("c", 3);String express = "a + b * c";Object r = runner.execute(express, context, null, true, false);System.out.println(r);runner.addOperatorWithAlias("如果", "if", null);runner.addOperatorWithAlias("则", "then", null);runner.addOperatorWithAlias("否则", "else", null);express = "如果 (语文 + 数学 + 英语 > 270) 则 {return 1;} 否则 {return 0;}";Object o = runner.execute(express, context, null, false, false, 50);System.out.println(o);/*runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs", new String[] {"double"}, null);runner.addFunctionOfClassMethod("转换为大写", BeanExample.class.getName(), "upper", new String[] {"String"}, null);runner.addFunctionOfServiceMethod("打印", System.out, "println", new String[] { "String" }, null);runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains", new Class[] {String.class, String.class}, null);String express1 = "取绝对值(-100); 转换为大写(\"hello world\"); 打印(\"你好吗?\"); contains(\"helloworld\",\"aeiou\")";Object e = runner.execute(express1, context, null, false, false);System.out.println(e);*/}
}
运行结果:
Connected to the target VM, address: '127.0.0.1:11215', transport: 'socket'
7
1
Disconnected from the target VM, address: '127.0.0.1:11215', transport: 'socket'
6.3resource下新建qLrules文件夹,新建并编写rule.ql文件
是否符合 = 1;
运费 = 0;
最长边 = 长 > 宽 ? 长 : 宽;
最长边 = 最长边 > 高 ? 最长边 : 高;
最短边 = 长 < 宽 ? 长 : 宽;
最短边 = 最短边 < 高 ? 最短边 : 高;
中间边 = (长 + 宽 + 高) - 最长边 - 最短边;
围长 = (中间边 + 最短边) * 2 + 最长边;
如果 (围长 > 300) 则{是否符合 = 0;return 是否符合;
}
如果 (最长边 > 175) 则{是否符合 = 0;return 是否符合;
}
如果 (30 >= 重量 ) 则{是否符合 = 0;return 是否符合;
}
如果 (30 < 重量 ) 则{是否符合 = 0;运费 = 1.5*(重量-30);return 是否符合;
}
6.4编写测试用例
@Test
public void ruleTest() throws Exception {List<String> ruleFileNames = new ArrayList<>();ruleFileNames.add("qLrules/rule.ql");for (int i = 0; i < ruleFileNames.size(); i++) {String script = getResourceAsStream(ruleFileNames.get(i));ExpressRunner runner = new ExpressRunner(false, false);runner.addOperatorWithAlias("如果", "if", null);runner.addOperatorWithAlias("则", "then", null);runner.addOperatorWithAlias("否则", "else", null);IExpressContext<String, Object> context = new DefaultContext<>();try {context.put("长", 2);context.put("宽", 20);context.put("高", 40);context.put("重量", 35);context.put("COUNTRY","IS");runner.execute(script, context, null, true, false);System.out.println("文件名称:" + ruleFileNames.get(i));System.out.println("最长边:" + context.get("最长边"));System.out.println("中间边:" + context.get("中间边"));System.out.println("最短边:" + context.get("最短边"));System.out.println("是否符合:" + context.get("是否符合"));System.out.println("运费:" + context.get("运费"));} catch (Exception e) {e.printStackTrace();//Assert.assertTrue(e.toString().contains("at line 7"));}}
}
运行结果:
Connected to the target VM, address: '127.0.0.1:13783', transport: 'socket'
文件名称:qLrules/rule.ql
最长边:40
中间边:20
最短边:2
是否符合:0
运费:7.5
Disconnected from the target VM, address: '127.0.0.1:13783', transport: 'socket'
7.Apache Camel简介
Apache Camel是Apache基金会下的一个开源项目,它是一个基于规则路由和中介的规则引擎。包括基于Java的Fluent API,Spring或者Blueprint XML配置文件,甚至是Scala(是一种基于JVM,集合了面向对象编程和函数式编程优点的高级程序设计语言)DSL。 能够通过IDE或者Java、Scala或者XML编辑器里获得智能化路由规则补全功能。
Apache Camel可以做到:
路由:将数据有效负载(也称为“消息”)从源系统发送到目标系统。from().to().to()。
中介:消息处理,如基于一个或多个消息属性过滤消息、修改消息的某些字段、通过API调用进行充实等。
在面向服务的体系结构的项目中,Camel通常与Apache ServiceMix, Apache ActiveMQ以及Apache CXF一同使用。
◆ 适合使用Apache Camel的场景:
- 具有丰富组件集的Apache Camel对于需要通过不同协议(如文件、api或JMS队列)与系统集成的应用程序非常有用。
- Apache Camel的实现了企业集成模式,满足非常复杂的集成场景。
- 微服务中的编排和编排可以用Apache Camel路由中的领域特定语言来定义。路由有助于保持核心业务逻辑与通信逻辑解耦,并满足SRP(单一责任原则)。
- Apache Camel非常适合Java和Spring应用程序。
- 使用Java对象(pojo): Apache Camel是一个Java框架,因此它特别擅长使用Java对象。因此,如果使用的是XML、JSON等文件格式,可以反序列化为Java对象,那么Camel就可以轻松地对其进行处理。
◆ 不适合使用Apache Camel的场景:
- 如果我们的集成只是简单调用少量api
- Camel在处理大量数据时表现不佳
- Camel也不适合缺乏Java技能的团队
一般来说,camel的最佳用例是,有一个数据源,我们希望从其中消费数据,比如队列上的传入消息,或者从API和目标中获取数据,我们希望将数据发送到这些数据源。