当前位置: 首页 > article >正文

EasyRules:轻量级规则引擎的实战入门

1. 为什么你需要了解EasyRules如果你是一名开发者肯定遇到过这样的场景业务逻辑越来越复杂代码里充斥着大量的if-else嵌套每次修改都要小心翼翼生怕影响其他逻辑。我曾经维护过一个用户积分系统光是判断用户等级就有十几层条件判断后来新增一个特殊会员类型时差点把原有逻辑改崩。这时候你就需要一个规则引擎来解救你。但传统的规则引擎如Drools学习曲线陡峭配置复杂对于中小型项目来说有点杀鸡用牛刀的感觉。EasyRules就是为解决这个问题而生的轻量级方案它的核心代码只有几个类学习成本低却能帮你把业务规则从代码中彻底解耦。我最近在一个电商促销系统中使用EasyRules实现了优惠券规则管理原本需要一周开发的功能用EasyRules两天就搞定了而且后续业务调整时产品经理直接改YAML配置文件就能上线新规则再也不用等着开发排期了。2. 快速理解EasyRules核心概念2.1 三大核心组件EasyRules的核心设计非常简洁主要包含三个关键组件Fact可以理解为事实数据就是你的业务对象。比如在用户积分场景中用户的当前积分、注册时长、最近消费金额等都可以作为Fact。在代码中通常用Map或者POJO来表示。Rule规则的定义包含条件(condition)和动作(action)两部分。当条件满足时就会执行对应的动作。比如如果用户积分大于1000则升级为黄金会员就是一条典型规则。RulesEngine规则引擎负责评估所有规则并执行符合条件的动作。EasyRules提供了两种引擎实现默认引擎会按顺序执行所有符合条件的规则而流式引擎则会在第一条符合条件的规则执行后就停止。// 示例用Map存储Fact MapString, Object facts new HashMap(); facts.put(userScore, 1200); facts.put(userAge, 2); // 示例一个简单的Rule定义 Rule(name goldUserRule, description 如果积分超过1000就是黄金用户) public class GoldUserRule { Condition public boolean when(Fact(userScore) int score) { return score 1000; } Action public void then() { System.out.println(恭喜升级为黄金会员); } }2.2 与传统if-else的对比为了更直观地理解EasyRules的价值我们来看一个实际对比。假设要实现以下业务规则积分≥1000黄金会员积分≥500且注册满1年白银会员积分≥200青铜会员传统if-else实现if(score 1000) { user.setLevel(gold); } else if(score 500 user.getRegisterYears() 1) { user.setLevel(silver); } else if(score 200) { user.setLevel(bronze); }使用EasyRules实现Rule(name goldRule, priority 1) public class GoldRule { Condition public boolean when(Fact(score) int score) { return score 1000; } Action public void then() { user.setLevel(gold); } } Rule(name silverRule, priority 2) public class SilverRule { Condition public boolean when(Fact(score) int score, Fact(registerYears) int years) { return score 500 years 1; } Action public void then() { user.setLevel(silver); } } // 其他规则类似...优势显而易见规则之间完全解耦新增或修改规则不会影响其他规则规则定义更接近自然语言可读性更好规则可以动态加载无需重新部署应用。3. 三种方式玩转规则定义EasyRules最强大的地方在于它提供了多种规则定义方式适应不同场景需求。下面我就以用户积分等级评定为例分别演示三种主流方式。3.1 注解方式最适合Java开发者注解方式是最直观的Java原生支持方式适合规则相对固定的场景。我在实际项目中最常用的就是这种方式它的优点是类型安全IDE支持好重构方便。Rule(name vipRule, description 特殊VIP用户规则, priority 1) public class VipUserRule { Condition public boolean isVip( Fact(score) int score, Fact(consumption) double consumption) { return score 5000 || consumption 10000; } Action public void setVip() { user.setVip(true); System.out.println(授予VIP身份); } } // 使用方式 RulesEngineParameters params new RulesEngineParameters() .skipOnFirstAppliedRule(true); // 使用流式引擎 RulesEngine engine new DefaultRulesEngine(params); Rules rules new Rules(); rules.register(new GoldUserRule()); rules.register(new VipUserRule()); engine.fire(rules, facts);实战技巧通过priority属性控制规则执行顺序数字越小优先级越高使用skipOnFirstAppliedRule参数可以开启流式模式匹配到第一条规则后就停止规则类可以像普通Spring Bean一样被管理方便集成到现有系统中3.2 流式API适合动态规则构建当你需要根据运行时条件动态构建规则时流式API是不二之选。我曾经做过一个动态促销系统规则需要根据库存情况实时调整流式API完美解决了这个问题。Rule weatherRule new RuleBuilder() .name(weatherPromotionRule) .description(下雨天雨伞打折) .when(facts - rainy.equals(facts.get(weather))) .then(facts - { product.setDiscount(0.8); System.out.println(启动雨天促销); }) .build(); Rule stockRule new RuleBuilder() .name(clearanceRule) .description(库存清理规则) .when(facts - (int)facts.get(stock) 1000) .then(facts - { product.setDiscount(0.6); System.out.println(启动清仓促销); }) .build(); Rules rules new Rules(); rules.register(weatherRule); rules.register(stockRule); engine.fire(rules, facts);适用场景规则需要根据用户输入或其他运行时条件动态生成规则条件简单不需要复杂逻辑判断需要快速原型开发时3.3 YAML配置业务人员友好的方式YAML方式是我最推荐给需要业务人员参与规则配置的场景。产品经理可以直接修改YAML文件调整业务规则完全不需要开发介入。在我们的电商系统中促销规则都是用这种方式管理的。name: newUserRule description: 新用户首单优惠 priority: 1 condition: user.new true order.first true actions: - order.discount 0.9 - system.out.println(新用户首单享受9折)加载YAML规则Rules rules YamlRuleFactory.createRulesFrom( new File(rules/new-user-rule.yml)); engine.fire(rules, facts);最佳实践将不同业务领域的规则放在不同的YAML文件中使用版本控制管理规则变更历史可以配合Spring Cloud Config实现规则的热更新4. 实战用户积分等级系统现在让我们把这些知识综合起来实现一个完整的用户积分等级系统。这个案例来自我实际参与过的一个会员体系重构项目。4.1 系统需求分析我们需要实现以下业务规则基础等级规则积分≥5000钻石会员积分≥3000白金会员积分≥1000黄金会员积分≥500白银会员积分≥100青铜会员特殊规则连续签到7天提升一个等级最高到黄金最近30天消费满5000元直接升级为白金降级规则连续90天无消费降一级积分低于当前等级要求降级到对应等级4.2 实现步骤首先定义我们的Fact对象public class User { private String userId; private int score; private String level; private int consecutiveCheckins; private double last30DaysConsumption; private LocalDate lastConsumptionDate; // getters/setters }然后实现核心规则以注解方式为例Rule(name diamondRule, priority 1) public class DiamondRule { Condition public boolean when(Fact(user) User user) { return user.getScore() 5000; } Action public void then(Fact(user) User user) { if(!diamond.equals(user.getLevel())) { user.setLevel(diamond); sendNotification(user, 恭喜升级为钻石会员); } } } Rule(name checkinBoostRule, priority 10) public class CheckinBoostRule { Condition public boolean when(Fact(user) User user) { return user.getConsecutiveCheckins() 7 !gold.equals(user.getLevel()); } Action public void then(Fact(user) User user) { String newLevel calculateUpgradedLevel(user.getLevel()); user.setLevel(newLevel); user.setConsecutiveCheckins(0); // 重置签到计数 } private String calculateUpgradedLevel(String current) { // 升级逻辑实现 } }最后是引擎配置和执行public class LevelService { private RulesEngine engine; private Rules rules; PostConstruct public void init() { engine new DefaultRulesEngine( new RulesEngineParameters() .skipOnFirstNonTriggeredRule(false)); rules new Rules(); rules.register(new DiamondRule()); rules.register(new CheckinBoostRule()); // 注册其他规则... } public void evaluate(User user) { Facts facts new Facts(); facts.put(user, user); engine.fire(rules, facts); } }4.3 遇到的坑与解决方案在实际实现过程中我遇到过几个典型问题规则执行顺序问题最初没有设置priority导致降级规则先于升级规则执行。解决方案是为所有规则明确设置优先级确保升级规则先执行。性能问题当规则数量超过100条时引擎执行时间明显变长。通过以下方式优化将规则按业务领域分组不同场景使用不同的规则组使用skipOnFirstNonTriggeredRule参数减少不必要的评估对高频规则设置更高的优先级规则冲突问题两条规则的条件有重叠时可能产生冲突。我们引入了规则冲突检测机制在测试阶段就发现并解决这类问题。5. 进阶技巧与最佳实践经过多个项目的实践我总结出以下经验能帮你更好地使用EasyRules。5.1 如何组织大型规则集当规则数量增多时良好的组织方式至关重要按业务领域分包例如将用户相关规则放在user包下订单规则放在order包下。使用规则组通过组合模式将相关规则打包Rules userLevelRules new Rules(); userLevelRules.register(new GoldRule()); userLevelRules.register(new SilverRule()); Rules promotionRules new Rules(); promotionRules.register(new CouponRule()); promotionRules.register(new DiscountRule()); // 按需执行不同规则组 engine.fire(userLevelRules, userFacts); engine.fire(promotionRules, orderFacts);版本化管理为规则定义版本号支持多版本规则共存便于灰度发布和回滚。5.2 测试策略规则引擎的测试需要特别关注单元测试每个规则确保每个规则的condition和action都正确Test public void testGoldRule() { // 准备 GoldRule rule new GoldRule(); User user new User(); user.setScore(1200); Facts facts new Facts(); facts.put(user, user); // 执行 验证 assertTrue(rule.when(facts)); rule.then(facts); assertEquals(gold, user.getLevel()); }集成测试规则组合验证多个规则一起执行时的效果。性能测试模拟生产环境的数据量确保引擎性能达标。5.3 与Spring集成在Spring项目中使用EasyRules非常方便将规则类声明为Spring组件Component Rule(name springRule) public class SpringIntegrationRule { Autowired private UserService userService; // 规则实现... }自动发现并注册所有规则Configuration public class RulesConfig { Autowired private ListObject ruleBeans; // 收集所有带有Rule注解的Bean Bean public Rules rules() { Rules rules new Rules(); ruleBeans.forEach(rules::register); return rules; } }在Service中使用Service public class UserLevelService { Autowired private RulesEngine engine; Autowired private Rules rules; public void evaluateUser(User user) { Facts facts new Facts(); facts.put(user, user); engine.fire(rules, facts); } }6. 什么时候该用或不该用EasyRules虽然EasyRules很强大但它并不是银弹。根据我的经验以下场景特别适合使用EasyRules业务规则频繁变更比如促销活动、费率计算等经常需要调整的业务逻辑。需要业务人员参与规则配置通过YAML方式让非技术人员也能参与规则管理。规则数量中等几十到几百条规则太多时可能需要考虑更专业的规则引擎。而不适合的场景包括超高性能要求规则引擎毕竟有额外开销对性能要求极高的核心链路可能需要更直接的代码实现。非常简单的业务逻辑只有两三条固定规则时直接if-else可能更简单。需要复杂的规则推理如需要处理复杂的规则网络和推理链时Drools等更专业的引擎会更合适。

相关文章:

EasyRules:轻量级规则引擎的实战入门

1. 为什么你需要了解EasyRules? 如果你是一名开发者,肯定遇到过这样的场景:业务逻辑越来越复杂,代码里充斥着大量的if-else嵌套,每次修改都要小心翼翼,生怕影响其他逻辑。我曾经维护过一个用户积分系统&…...

HoRain云--PHP安全插入MySQL数据指南

🎬 HoRain 云小助手:个人主页 ⛺️生活的理想,就是为了理想的生活! ⛳️ 推荐 前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。 目录 ⛳️ 推荐 …...

如何安全导出浏览器Cookie:本地化工具的完整使用教程

如何安全导出浏览器Cookie:本地化工具的完整使用教程 【免费下载链接】Get-cookies.txt-LOCALLY Get cookies.txt, NEVER send information outside. 项目地址: https://gitcode.com/gh_mirrors/ge/Get-cookies.txt-LOCALLY 你是否曾需要将浏览器Cookie导出到…...

利用 JiuwenClaw AgentTeam 打造自动化研发团队

利用 JiuwenClaw AgentTeam 打造自动化研发团队 本文介绍如何通过 JiuwenClaw AgentTeam 构建自动化研发团队,实现字幕软件开发、AtomGit Issue/PR 智能处理与飞书文档同步。 目录 JiuwenClaw 平台概述 系统架构预置智能体类型 什么是 AgentTeams飞书群中添加机器人…...

AI时代就业真相:小白程序员如何抓住大模型机遇,收藏这份必看指南!

智联招聘数据显示,AI短期内替代部分岗位,但新增岗位同样显著。编辑、翻译等白领岗位需求缩减,而AI工程师、数据标注师等需求激增。初级职位衰减,中级与高级职位增长,企业招聘更看重软技能与AI应用能力。建议关注新质生…...

别再死记硬背了!通过eNSP搭建WLAN,一次搞懂AC+AP架构中的VLAN、CAPWAP和业务转发

从零构建企业级WLAN:ACAP架构中的关键技术解析与实战 在数字化转型浪潮中,无线网络已从简单的"能上网"演变为支撑业务运营的关键基础设施。对于网络工程师而言,理解ACAP架构背后的设计哲学,远比记住配置命令更为重要。本…...

转转前端周刊第194期: 裁员潮将持续,直到我们学会发掘 AI 的商业价值

转转前端周刊本刊意在将整理业界精华文章给大家,期望大家一起打开视野1、裁员潮将持续,直到我们学会发掘 AI 的商业价值本文以亲历者视角切入 AI 裁员潮的现实焦虑,剖析了从 Coinbase 到 Square 等一系列"AI 裁员"事件背后的商业逻…...

5个关键步骤让zotero-pdf-translate翻译功能重新工作:完整解决方案指南

5个关键步骤让zotero-pdf-translate翻译功能重新工作:完整解决方案指南 【免费下载链接】zotero-pdf-translate Translate PDF, EPub, webpage, metadata, annotations, notes to the target language. Support 20 translate services. 项目地址: https://gitcode…...

Beyond Compare 5完全激活指南:3种简单方法告别30天试用限制

Beyond Compare 5完全激活指南:3种简单方法告别30天试用限制 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否正在使用Beyond Compare 5这款强大的文件对比工具,却因…...

从数据焦虑到数字资产:WeChatExporter如何重塑你的微信记忆管理

从数据焦虑到数字资产:WeChatExporter如何重塑你的微信记忆管理 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 你是否曾因手机存储空间不足而不得不删除珍贵…...

PS2021神经滤镜离线包保姆级安装指南(附文件夹显示与路径详解)

PS2021神经滤镜离线包安装全流程实战手册 第一次打开Photoshop 2021的神经滤镜功能时,那个漫长的下载进度条简直让人崩溃。特别是当网络环境不稳定时,下载失败的概率直线上升。其实Adobe官方提供了完整的离线安装方案,只是隐藏得比较深——就…...

Java程序开发第七课

1. Java基础入门 Java特点:跨平台(JVM)、面向对象、健壮性(强类型、垃圾回收)。JDK、JRE、JVM关系: JDK (开发工具包) JRE 开发工具 (javac, java&#x…...

Pinecone示例库实战指南:从向量数据库原理到RAG应用开发

1. 项目概述:Pinecone示例库的深度探索 如果你正在寻找一个能让你快速上手向量数据库和现代AI应用开发的“实战训练营”,那么Pinecone官方的 pinecone-io/examples 仓库绝对是一个不容错过的宝藏。这个仓库远不止是一个简单的代码合集,它更…...

从DesignCon 2011看EDA技术演进:高速链路、低功耗与3D-IC设计启示

1. 从一场行业盛会看电子设计的未来风向每年年初,硅谷的心脏地带——加州圣克拉拉,都会迎来一场电子设计自动化(EDA)与半导体设计领域的年度盛事:DesignCon。对于像我这样在硬件设计领域摸爬滚打了十几年的工程师来说&…...

基于Hammerspoon的macOS光标高亮定位工具实现与优化

1. 项目概述:一个让你不再“找光标”的效率神器你有没有过这样的经历?在27寸甚至更大的显示器上,或者是在多屏工作环境中,眼睛在密密麻麻的代码、文档和浏览器标签之间快速扫视,突然,那个小小的鼠标光标“消…...

分形超材料实现电磁波绕障传输:原理、实验与射频应用

1. 项目概述:让信号“穿墙”的隐身斗篷如果你看过《星际迷航》,肯定对克林贡人或罗慕伦人的隐形装置印象深刻,它能让整艘飞船从雷达上消失。虽然我们还没法让宏观物体真正“隐形”,但在电磁波的世界里,让信号“无视”一…...

终极图形化方案:Applite如何让Mac软件管理变得简单快速

终极图形化方案:Applite如何让Mac软件管理变得简单快速 【免费下载链接】Applite User-friendly GUI macOS application for Homebrew Casks 项目地址: https://gitcode.com/gh_mirrors/ap/Applite 还在为Mac上的软件安装、更新和卸载而烦恼吗?Ap…...

Godot 4.x ECS插件GECS:数据驱动架构提升游戏性能与可维护性

1. 项目概述:GECS,为Godot 4.x注入ECS架构之力如果你正在用Godot开发游戏,尤其是那种实体数量多、交互逻辑复杂的项目,比如RTS、模拟经营或者一个满屏敌人的弹幕游戏,你很可能已经感受到了传统面向对象(OOP…...

如何快速解包Godot游戏资源:3分钟掌握PCK文件提取技巧

如何快速解包Godot游戏资源:3分钟掌握PCK文件提取技巧 【免费下载链接】godot-unpacker godot .pck unpacker 项目地址: https://gitcode.com/gh_mirrors/go/godot-unpacker 你是否曾经遇到过想要查看Godot游戏内部资源却无从下手的困境?那些神秘…...

Helm 2到Helm 3迁移实战:深入解析helm-2to3插件原理与操作指南

1. 项目概述与背景 如果你和我一样,在Kubernetes生态里摸爬滚打了几年,那你一定对Helm这个“包管理器”又爱又恨。爱的是它用声明式的Chart把复杂的应用部署变得像 helm install 一样简单;恨的是版本升级带来的“阵痛”,尤其是从…...

从‘方波变形记’聊起:为什么你的高速信号需要Tx EQ?一个给嵌入式软件/FPGA工程师的通俗图解

从‘方波变形记’聊起:为什么你的高速信号需要Tx EQ? 想象一下,你正在观看一场高清直播,画面突然出现马赛克;或者传输重要数据时,系统频繁报错。这些问题的根源,可能就藏在信号传输的微观世界里…...

告别虚拟机!Windows 11下用Conda一键安装GNU Radio 3.10(附国内镜像加速)

Windows 11下用Conda极速部署GNU Radio 3.10全攻略 在软件无线电(SDR)领域,GNU Radio一直是开源工具链中的标杆。但许多Windows用户在初次接触时,往往被复杂的依赖关系和繁琐的安装过程劝退。虚拟机卡顿、版本兼容性问题、依赖冲突…...

AutoResearchClaw:基于LLM的自动化研究管线,从想法到论文的工程化实践

1. 项目概述:从“聊个想法”到“生成论文”的自动化研究革命如果你是一名科研工作者、研究生,或者任何需要产出高质量学术内容的人,你肯定经历过这样的痛苦:一个绝妙的研究想法在脑海中诞生,但随之而来的是海量的文献调…...

深度清理工具openclaw-uninstaller:跨平台卸载与Node.js生态清理指南

1. 项目概述:为什么我们需要一个专门的卸载工具?在软件开发和日常使用中,卸载一个应用程序听起来像是一个简单的“删除”操作,但实际情况往往复杂得多。尤其是那些功能强大、深度集成到系统中的工具,比如涉及3D重建、A…...

基于React+TypeScript+Tailwind的ChatGPT应用UI模板开发指南

1. 项目概述:一个为ChatGPT应用量身定制的UI模板如果你正在开发一个基于ChatGPT或类似大语言模型的Web应用,无论是客服机器人、智能写作助手,还是企业内部的知识问答工具,那么你大概率会遇到一个绕不开的难题:如何快速…...

Onyx:基于Next.js 14的全栈MVP模板,集成Supabase与现代化工具链

1. 项目概述:Onyx,一个开箱即用的全栈Next.js 14 MVP模板如果你正在寻找一个能让你在几天内,而不是几周内,就启动一个现代化、功能齐全的Web应用原型的起点,那么Onyx很可能就是你需要的那个“瑞士军刀”。这不是一个简…...

AI技能gate-of-oss:智能海巡GitHub,高效开源项目选型

1. 项目概述:一个帮你“海巡”GitHub的AI技能在软件开发这个行当里,我敢说,几乎每个开发者都经历过这样的时刻:为了解决一个具体问题,或者想给项目引入一个新功能,一头扎进GitHub的汪洋大海,试图…...

PIM架构如何优化LLM推理中的内存墙问题

1. PIM架构核心原理与LLM推理瓶颈在传统冯诺依曼架构中,数据需要在处理器和内存之间频繁搬运,这种"内存墙"问题在大型语言模型(LLM)推理场景中尤为突出。处理内存计算(PIM)技术的革命性在于将计算单元直接嵌入内存控制器附近,通过近…...

vLLM Semantic Router:基于信号驱动的LLM智能路由架构与生产实践

1. 项目概述:为什么我们需要一个“智能”的LLM路由器?在当前的LLM应用开发中,我们正面临一个甜蜜的烦恼:模型太多了。从闭源的GPT-4、Claude,到开源的Llama、Qwen、DeepSeek,再到各种针对特定任务微调的小模…...

LLM Workflow Engine:命令行AI工作流引擎的架构与实战

1. 项目概述:从命令行到工作流,一个LLM引擎的进化如果你和我一样,是个重度命令行用户,同时又对大型语言模型(LLM)的潜力着迷,那你肯定经历过这种纠结:想快速用GPT-4验证一个想法&…...