RulesEngine
什么是RulesEngine
RulesEngine 是微软开源的一个轻量级规则引擎框架,用于在 .NET 应用中执行业务规则。它允许开发者将复杂的业务逻辑从代码中解耦出来,通过定义规则集合来灵活地处理各种业务场景。
核心特性
- JSON 驱动:规则以 JSON 格式定义,支持动态加载和修改
- 表达式计算:支持复杂的条件表达式评估
- 嵌套规则:支持规则之间的嵌套和组合
- 输入参数映射:灵活地将对象属性映射到规则执行上下文
- 可扩展性:提供自定义操作符和函数的机制
RulesEngine 如何工作
1. 核心架构
RulesEngine 的执行流程遵循以下设计:
1
输入数据 → 参数映射 → 规则编译 → 条件评估 → 动作执行 → 输出结果
2. 关键组件
RulesEngine 类
这是框架的核心入口,主要职责:
- 管理规则工作流(Workflow)
- 执行规则并返回结果
- 维护规则的生命周期
Workflow 工作流
- 包含多个 Rule 对象
- 按顺序执行规则
- 支持并行处理
Rule 规则
- 由名称、条件和动作组成
- 条件(RuleExpressionType)决定是否执行动作
- 支持嵌套规则(Sub Rules)
RuleExpression 规则表达式
- 定义规则的执行条件
- 支持的表达式类型:
Lambda:lambda 表达式Inline:内联表达式(关键字+操作符+值)
3. 核心执行机制
参数处理
1
输入对象 → ReflectionUtils → 提取属性值 → 存储到执行上下文
RulesEngine 使用反射机制遍历输入对象的属性,将其转换为规则引擎能理解的参数形式。
表达式评估
- Lambda 表达式:直接使用 Expression Trees 编译执行
- Inline 表达式:通过操作符解析器(如
Contains、GreaterThan、In等)转换为委托执行
动作执行
- 动作(Action)是规则条件满足时执行的逻辑
- 支持多个动作的依次执行
- 动作可以修改输出数据或触发其他规则
4. 规则编译过程
RulesEngine 采用延迟编译策略:
- 规则首次执行时进行编译
- 编译结果被缓存以提高后续执行性能
- 使用 Expression Trees 构建委托,避免每次都解析规则
为什么这样设计
1. 为什么使用 JSON 格式存储规则?
优势:
- 易于持久化:可存储在数据库、配置文件或其他介质
- 动态加载:无需重新编译代码,运行时修改规则
- 可读性强:非技术人员也能理解规则逻辑
- 跨平台兼容:JSON 作为通用格式,便于集成
2. 为什么设计参数映射机制?
规则引擎需要处理各种形式的输入数据(对象、字典、基本类型等),参数映射提供:
- 统一的数据抽象:屏蔽输入数据的具体形式
- 灵活的属性访问:支持嵌套属性和集合操作
- 类型安全性:在编译时进行类型验证
3. 为什么使用表达式树(Expression Trees)?
- 高性能:编译为机器代码,执行速度接近原生 C# 代码
- 动态性:在运行时构建和编译表达式
- 可组合性:支持复杂表达式的组合和优化
4. 为什么要支持嵌套规则?
- 规则复用:避免重复定义相同的逻辑
- 模块化设计:提高规则的可维护性和组织性
- 业务灵活性:应对复杂业务场景需要多层次的决策
5. 为什么采用延迟编译?
- 启动性能:避免在应用启动时编译所有规则
- 内存优化:只编译被执行的规则
- 灵活更新:规则修改后,下次执行时自动重新编译
设计模式与原理
应用的设计模式
- Builder 模式:规则的构建使用 FluentAPI,链式调用配置规则属性
- Strategy 模式:不同的表达式类型采用不同的计算策略
- Factory 模式:操作符工厂创建对应的表达式计算器
- Compiler 模式:表达式动态编译为委托
核心原理
反射与元数据
- 运行时获取对象属性信息
- 支持嵌套属性访问(如
User.Address.City) - 处理集合和可空类型
表达式树优化
- 构建抽象语法树(AST)
- 编译优化(常量折叠、死代码消除等)
- 生成高效的委托
缓存策略
- 规则编译结果缓存
- 减少重复编译开销
- 支持缓存失效机制
总结
RulesEngine 通过以下核心设计实现了一个高效、灵活的规则引擎:
- 分离关注点:业务规则与业务逻辑解耦
- 动态性:支持运行时规则修改和加载
- 性能:通过表达式树编译和缓存实现高性能
- 可扩展性:提供自定义操作符和规则的机制
- 易用性:简洁的 API 和 JSON 配置
这些设计使得 RulesEngine 成为处理复杂业务规则的理想选择,特别是在需要频繁修改业务逻辑的场景中。
本文由作者按照 CC BY 4.0 进行授权