规则引擎简介
在企业应用中,经常需要根据一组业务规则进行操作和决策。硬编码这些规则直接到应用程序中,不仅会使得代码难以管理,还会导致业务逻辑与应用逻辑的混合,降低了系统的灵活性和可维护性。规则引擎的出现,正是为了解决这些问题。
1.1 什么是规则引擎?
规则引擎是一种软件系统,它使用定义好的业务规则来评估和执行相应的行为。它通常用于实现动态决策过程,使得规则可以在不更改应用程序代码的情况下进行修改和扩展。
1.2 规则引擎的优势
解耦业务逻辑:将业务规则从程序代码中分离,提高了代码的清晰度和可维护性。
灵活性增强:业务规则更改时,无需重新编译代码,提供了更高的业务灵活性。
业务逻辑集中管理:所有的业务规则集中存储和管理,便于审查、版本控制和一致性检查。
复杂决策处理:规则引擎可以处理复杂的决策逻辑,支持多个条件和动作的组合,使得复杂业务逻辑的实现更加简洁和直观。
1.3 常见的Java规则引擎区别
以下是基于使用人数、社区活跃度和使用规模排序,整理出的常见的Java规则引擎,Drools、Easy Rules、Esper、OpenRules和JRuleEngine五个Java规则引擎的区别
排名 | 规则引擎 | 特性与区别 | 优点 | 缺点 |
---|---|---|---|---|
1 | Drools | 丰富的功能集(复杂事件处理、规则流、决策表等),广泛使用,企业级解决方案 | 功能强大、广泛的社区支持、良好的文档、支持复杂规则 | 学习曲线陡峭、复杂的配置、潜在的性能开销 |
2 | Esper | 高性能复杂事件处理引擎,适用于实时数据流和事件流 | 高性能、适合实时数据处理、支持复杂事件处理 | 学习曲线较陡、针对特定场景(事件处理)的应用更为适合 |
3 | OpenRules | 商业规则管理系统,支持用户定义和管理业务规则,适用于业务用户和开发人员 | 用户友好、强大的规则管理功能、支持业务用户和开发人员的协作 | 商业软件,可能涉及费用、学习曲线取决于具体使用场景 |
4 | Easy Rules | 轻量级,易于使用和集成,适合处理简单规则 | 简洁易用、学习曲线平缓、轻量级、快速上手 | 功能有限、不适合处理复杂规则、社区支持相对较少 |
5 | JRuleEngine | 基于Java的开源规则引擎,支持基于XML定义的规则 | 开源免费、简单易用、基于XML定义规则 | 社区和文档支持相对较少、功能相对简单、不适合处理非常复杂的规则 |
规则引擎有很多,大家根据根据自己的需求,项目需求,开发人员技术栈来选择合适规则引擎时开发。
下面的话,我们主要以Easy Rules规则引擎展开讲述。
Java Easy Rules规则引擎
2.1 概述
Easy Rules 是一个用Java编写的简单而强大的规则引擎,旨在简化规则引擎的使用。它的设计目标是使得开发者能够轻松上手,并能够快速实施业务逻辑。
2. 2 主要特性
- 轻量级:Easy Rules 是轻量级的,没有复杂的依赖,可以很方便地集成到任何Java应用中。
- 易于使用:提供简洁的API,业务规则可以以简单的Java对象或MVEL表达式形式定义。
- 灵活性:支持复合规则、条件规则和动作规则,可以处理复杂的业务逻辑。
- 可扩展性:通过添加新的规则来扩展系统功能。
2.3 如何使用 Easy Rules
2.3.1 引入依赖
在你的 pom.xml
文件中添加以下依赖:
<!-- Easy Rules 核心库依赖 -->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>4.1.0</version>
</dependency>
<!-- Easy Rules MVEL 扩展库依赖 -->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>4.1.0</version>
</dependency>
<!-- 解析文件,如json或者yml或各种其他工具类支持-->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-support</artifactId>
<version>4.1.0</version>
</dependency>
easy-rules-core
是 Easy Rules 的核心库,包括了规则引擎的主要功能和基础设施。它提供了定义、管理和执行规则的基本API和实现。
- 规则定义:允许你使用Java类或注解来定义规则。
- 规则管理:提供了规则注册和组织的功能。
- 规则执行:包含用于执行规则引擎的核心逻辑。
- 核心API:包含如 Rule, Rules, RulesEngine, Facts 等核心接口和类。
easy-rules-mvel
扩展了 Easy Rules,允许你使用 MVEL 表达式语言来定义规则。这使得规则可以以更加动态和灵活的方式定义,而不需要编写Java代码。
- MVEL 表达式:能够使用简单而强大的MVEL表达式来定义规则的条件和动作。
- 动态规则:可以在运行时加载和解析规则,不需要重新编译代码。
- 灵活性:适合那些需要高灵活性和动态配置的场景,特别是在规则定义需要频繁变化的系统中。
easy-rules-support
模块提供了一系列帮助类和功能,这些功能旨在简化和增强基于 Easy Rules 框架的规则引擎的开发。以下是该模块的一些主要功能:
- SpEL: 提供对 Spring Expression Language (SpEL) 的支持,使你可以使用 SpEL 来编写规则条件和执行操作。
- MVEL: 提供对 MVEL (MVFLEX Expression Language) 的支持,使你能够使用 MVEL 语言编写规则条件和执行操作。
- JMX 规则监控:支持通过 JMX (Java Management Extensions) 监控规则引擎,使你能够实时监控规则的执行情况。
- 规则引擎配置文件支持:允许从外部配置文件(例如 YAML 或 JSON 文件)加载规则,从而使规则定义更加灵活和易于管理。
- 其他辅助功能:提供了各种辅助类和实用工具,以简化规则的定义、管理和执行。
2.3.2 引子
假如我们有这么一个需求,
- 情况A:如果能被2整除的数,输出:我能被2整除;
- 情况B:如果能被3整除的数,输出:我能被3整除;
- 情况C:如果能被2整除的数且能被3整除的数,输出:我既可被2整除,也能被3整除;
只能输出一种情况,且情况C的优先级最高
。用java代码中的if–else-if实现的话
@Test
public void test1(){
int number = 12;
if (number % 2 == 0 && number % 3 == 0) {
//情况C
System.out.println("我既可被2整除,也能被3整除");
} else if (number % 2 == 0) {
//情况A
System.out.println("我能被2整除");
} else if (number % 3 == 0) {
//情况B
System.out.println("我能被3整除");
} else {
System.out.println("我既不能被2整除,也不能被3整除");
}
}
了解规则引擎,我们先了解几个概念,
facts:表示当前被传入的key:value结构的参数.它们可以是任何类型的对象,通常是领域模型对象
rule:代表一组特定条件和操作,它由条件(Conditions)和动作(Actions)组成。可以通过继承BasicRule类或使用@Rule注解来定义规则
Condition:是规则的前提条件,决定规则是否应该被触发。可以通过实现Condition接口或使用Lambda表达式来定义条件
Action:是当条件满足时应该执行的操作。可以通过实现Action接口或使用Lambda表达式来定义动作
那我们用EasyRules要怎么实现呢,下面通过多种方式实现。
定义规则
定义规则有多种方式,如:注解
,链式编程
,表达式
,yml配置文件
方式一:注解
@Rule注解
可以把规则理解为if语句和满足条件后的执行体,当 @Condition注解的方法返回真的时候则执行@Action注解的 方法
@Rule:写在Rule类上,标识这是一个规则,
可选参数:
- name(规则命名空间的唯一规则名称),
- description(描述规则的作用),
- priority(设置规则的优先级,值越低优先级越高,不设置默认为**-1**,可以通过这个设置默认的响应规则)
@Condition: 写在方法上作为判断条件,为真的时候返回True并执行**@Action方法,返回False**的时候则直接跳过
@Action:Condition:条件判断注解:如果return true, 执行Action
情况A: 能被2整除。
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
@Rule(name = "被2整除", description = "number如果被2整除,打印:我能被2整除;", priority = 1)
public class RuleA {
/**
* Condition:条件判断注解:如果return true, 执行Action
*/
@Condition
public boolean isA(@Fact("number") int number) {
return number % 2 == 0;
}
// Action 执行方法注解
@Action
public void aAction(@Fact("number")int number) {
System.out.println("打印:"+number+"能被2整除;");
}
}
情况B: 能被3整除。
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation