JVM 规则引擎全家桶:从入门到选型本次搜索时间:2026-03-31 | 数据来源:GitHub 官方仓库及 Release Notes一、背景与定位在 Java 业务系统开发的漫长历史中,"业务规则频繁变更"始终是一个令人头疼的问题。营销活动的价格策略要调整、风险控制的门槛要修改、会员等级的判定逻辑要更新——每一次规则变更都意味着代码改动、测试验证、发版部署,周期长、风险高、响应慢。尤其是高并发交易系统,规则的热切换能力直接影响业务运营的灵活性和竞争力。规则引擎(Rule Engine)正是为解决这一问题而生的核心技术。它将业务决策逻辑从应用程序代码中分离出来,以数据的形式存储在数据库或配置中心,支持在运行时动态加载和执行。业务人员可以参与规则配置,无需工程师发版即可实时生效。然而,JVM 生态中的规则引擎方案极为多样,从几十 KB 的轻量表达式编译器(如 Janino)到几十 MB 的完整规则管理系统(如 Drools),定位、性能、功能复杂度差异悬殊。选错方案,小则影响开发效率,大则成为系统性能瓶颈。本文对6 个主流 JVM 规则引擎 / 表达式语言进行全面横向评测,所有数据基于 GitHub 官方仓库的最新 Release,时间截至 2026-03-31。其中重点对比AviatorScript和QLExpress——两者功能重叠度最高,是国内项目选型时最常纠结的两个选项。二、参战选手一览项目GitHub最新版本维护方JAR大小核心定位AviatorScriptkillme2008/aviatorscript5.4.3(2024-06)个人开源~1.3MB高性能脚本引擎 + 规则引擎QLExpressalibaba/QLExpress4.1.0(2025-02)阿里巴巴~250KB电商业务规则引擎MVELmvel/mvel3.0-alpha社区~500KB混合类型表达式语言Janinojanino-compiler/janinov3.1.6(2021-07)社区~300KBJava 源码即时编译器Droolsapache/drools9.xApache(孵化中)10MB完整 BRMS 规则管理系统SpELSpring Framework 内嵌—VMware随 SpringSpring 原生表达式语言三、性能与复杂度总览功能复杂度 上手难度(越高越右)JaninoSpELQLExpressAviatorScript(ASM)MVEL3GroovyDrools执行性能(越快越靠左)JaninoAviatorScript(ASM)QLExpressMVEL3SpELGroovyDrools从图中可以直观看到一个规律:性能越快的方案,功能越简单、扩展性越弱。这是一条铁律,选择哪个方案,本质上是在"性能"和"灵活性"之间做取舍。四、参战选手详细介绍4.1 AviatorScript 5.4.3 — 功能最全面的脚本引擎4.1.1 项目背景AviatorScript(GitHub 地址killme2008/aviatorscript)由个人开发者 dennis(killme2008)从 2010 年代初开始维护,至今已超过 15 年,是 Java 生态中持续活跃时间最长的脚本引擎之一。它的设计理念是"高性能 + 功能丰富 + 安全可控",定位明确指向需要动态脚本能力的生产系统。推荐最低版本为5.2.6,当前最新稳定版为5.4.3(2024年6月发布),带来了安全沙箱一键启用功能。AviatorScript 在国内有大量生产使用案例,尤其在数字货币交易所、电商促销系统、金融风控平台等技术选型中。它的核心优势在于同时提供了高性能执行(ASM 字节码)、丰富的语言特性(闭包、Sequence 抽象、高精度数字)、和可靠的安全机制(沙箱、超时、序列化缓存),是本文对比的六种方案中功能最均衡、最全面的选手。4.1.2 两种执行模式AviatorScript 最大的架构特点是支持两种完全不同的执行模式,这在所有 JVM 表达式引擎中是独一无二的。ASM 编译模式(默认)将脚本直接编译成 JVM 字节码,通过 ASM 框架生成java.lang.invoke.MethodHandle调用链。这是生产环境推荐使用的模式,执行性能最优,接近原生 Java 代码。编译过程在首次执行时完成,编译结果可以缓存复用。解释执行模式(Interpreter)从 5.3.0 版本引入,通过EvalMode.INTERPRETER实例化,在 AST 层面逐节点解释执行。性能比 ASM 模式低 5~10 倍,但可以运行在 Android、GraalVM Native Image 等非标准 Java 环境中。这一特性使得 AviatorScript 成为唯一可以在移动端使用的 JVM 脚本引擎。// ASM 模式(默认,生产环境推荐)AviatorEvaluatorInstanceasmEngine=AviatorEvaluator.getInstance();Expressionexp=asmEngine.compile("a + b 100",true);// 解释器模式(用于 Android 或非标准 JVM)AviatorEvaluatorInstanceinterpreterEngine=AviatorEvaluator.newInstance(EvalMode.INTERPRETER);Expressionexp2=interpreterEngine.compile("a + b 100",true);两种模式的切换只需要在创建引擎实例时指定EvalMode,API 完全兼容,代码几乎不需要改动。这是 AviatorScript 架构优雅之处——核心执行引擎与执行模式解耦,同一套 API 可以跑在两种完全不同的运行时上。4.1.3 核心语法示例基础表达式:Expressionexp=engine.compile("a + b * c 100 status == 'active'",true);Booleanresult=(Boolean)exp.execute(exp.newEnv("a",10,"b",20,"c",6,"status","active"));函数式编程 — reduce/map/filter 链式操作:// 计算持仓列表中,所有超过10万的订单的平均滑点letlarge=filter(positions,lambda(p)-p.amount100000end);lettotalSlippage=reduce(map(large,lambda(p)-p.slippage end),+,0);letavgSlippage=totalSlippage/count(large);avgSlippage0.5?3:1;字符串模板:"用户 #{userName} 积分 #{score}"// 支持 #{} 内嵌表达式4.1.4 自定义函数开发规范这是 Aviator 作为规则引擎最核心的扩展机制。开发者通过继承AbstractFunction并实现call()和getName()方法来定义自定义函数。以下是一个计算百分比的函数实现,展示了一个规范的自定义函数应该具备的全部要素:publicclassPercentageFunctionextendsAbstractFunction{@OverridepublicAviatorObjectcall(MapString,Objectenv,AviatorObjectdividend,AviatorObjectdivisor){doublediv=((Number)dividend.getValue(env)).doubleValue();doubledor=((Number)divisor.getValue(env)).doubleValue();// 必须处理除零异常,否则脚本会抛出难以追踪的运行时错误if(dor==0){thrownewIllegalArgumentException("divisor cannot be zero");}doublepct=div/dor*100;// 返回 AviatorDecimal,保证精度不丢失returnAviatorDecimal.valueOf(BigDecimal.valueOf(pct));}@OverridepublicStringgetName(){return"kb.percentage";// 脚本调用: kb.percentage(slippage, amount)}}// 应用启动时注册到引擎AviatorEvaluator.addFunction(newPercentageFunction());在实际项目中(参考 risk-manage-center 源码),常见的自定义函数还包括:kb.list_sum(列表字段求和)、kb.list_avg(列表字段求均值)、kb.list_filter_sum(过滤后求和)、kb.quick_open_close(快开快平检测)、kb.quick_price_difference(价格偏离度计算)。这些函数共同构成了业务规则脚本的"能力库",让脚本可以表达复杂的业务逻辑。4.1.5 安全机制执行超时(5.4.2+):AviatorEvaluator.setOption(Options.EVAL_TIMEOUT_MS,100);// 设置100ms超时,超过则抛出 TimeoutException超时机制是防止恶意脚本(如死循环)耗尽服务器资源的最后一道防线。在生产环境中,建议超时时间设置在 100~500ms 之间,具体取决于业务规则的复杂度。安全沙箱一键启用(5.4.3+):engine.enableSandboxMode();// 等价于同时配置多项安全限制:// - 禁止反射调用(Class.forName、getClass 等)// - 禁止访问文件系统(new FileInputStream 等)// - 禁止执行本地进程(Runtime.exec、ProcessBuilder 等)// - 禁止 Unsafe 类访问// - 禁止 socket 网络调用(部分高危 API)5.4.3 的enableSandboxMode()是 AviatorScript 历史上最重要的安全功能更新之一。在此前,配置沙箱需要手动设置多个选项,容易遗漏。新的一键 API 大幅降低了安全配置的心智负担。编译结果序列化(分布式缓存):engine.setOption(Options.SERIALIZABLE,true);Expressionexp=engine.compile("a b ? a : b",true);// 序列化到字节数组,存入 RedisByteArrayOutputStreamout=newByteArrayOutputStream();ObjectOutputStreamoos=engine.newObjectOutputStream(out);oos.writeObject(exp);byte[]bytes=out.toByteArray();// 另一个 JVM 进程反序列化使用,无需重新编译ByteArrayInputStreamin=newByteArrayInputStream(bytes);ObjectInputStreamois=engine.newObjectInputStream(in);Expressioncached=(Expression)ois.readObject();序列化缓存是 AviatorScript 在微服务架构中的杀手级特性。在传统架构中,每个微服务实例都需要独立编译规则表达式,造成了大量重复计算。通过 Redis 集中存储编译结果,所有实例共享一份缓存,既保证了规则的一致性,又消除了重复编译的开销。4.2 QLExpress 4.x — 阿里电商实战派4.2.1 项目背景QLExpress 由阿里巴巴于 2012 年开源,源自阿里电商业务的强需求——规则判断、布尔组合、高精度数学公式、脚本二次定制。在阿里集团内部有极大规模的应用,经受了双十一等极端流量场景的验证。2012年开源后在国内拥有大量用户,是国内活跃度最高的 JVM 规则引擎之一。2024年7月正式发布的4.x 版本是一次大规模重写(2023年12月进入 beta 测试阶段),全面迁移到 ANTLR4 语法解析器,API 设计大幅更新,是目前推荐的版本线。4.1.0(2025年2月)是截至搜索日期的最新版本,更新极为频繁,几乎每月都有新版本发布,社区响应速度极快。QLExpress 的核心优势是接地气——它不是学者们设计的理想化表达式语言,而是从真实业务需求中生长出来的工具。中文关键字、宏定义、阿里内部多年的踩坑经验,都融入了 QLExpress 的设计中。4.2.2 基础用法Express4Runnerrunner=newExpress4Runner(InitOptions.DEFAULT_OPTIONS);MapString,Objectcontext=newHashMap();context.put("a",1);context.put("b",2);context.put("c",3);Objectresult=runner.execute("a + b * c",context,QLOptions.DEFAULT_OPTIONS).getResult();// 7QLExpress 4.x 的 API 设计与 3.x 有显著变化。最显著的改进是返回值结构——现在通过QLResult对象返回结果,包含执行结果、错误信息等丰富上下文,不再像 3.x 那样直接返回 Object。4.2.3 自定义函数(Lambda 方式,4.x 推荐)4.x 版本废弃了 3.x 的addFunctionOfClassMethod等冗长 API,推荐使用 Lambda 表达式定义函数,大幅简化了代码:// 函数式自定义函数(推荐)runner.addVarArgsFunction("join",params-Arrays.stream(params).map(Object::toString).collect(Collectors.joining(",")));runner.execute("join(1, 2, 3)",Collections.emptyMap(),QLOptions.DEFAULT_OPTIONS).getResult();// "1,2,3"// 自定义操作符runner.addOperatorBiFunction("join",(left,right)-left+","+right);runner.execute("1 join 2 join 3",Collections.emptyMap(),QLOptions.DEFAULT_OPTIONS).getResult();// "1,2,3"4.2.4 高精度计算QLExpress 内置了智能精度识别:自动检测运算中是否存在无法用 double 精确表示的数字(如 0.1、0.2),一旦检测到则自动切换到 BigDecimal 运算,确保0.1 + 0.2 == 0.3成立。这对电商促销的折扣计算、金融系统的利息计算尤其重要。// 默认模式:自动精度提升runner.execute("0.3 == 0.1 + 0.2",Collections.emptyMap(),QLOptions.DEFAULT_OPTIONS).getResult();// true// 强制所有运算使用 BigDecimal(外部传入低精度数字时必须开启)runner.execute("0.3 == a + b",ctx,QLOptions.builder().precise(true).build()).getResult();4.2.5 四级安全策略QLExpress 4.x 的安全策略是其核心竞争力之一,提供了四级精细控制:isolation 模式(默认):完全隔离,不允许访问任何 Java 字段和方法。这是处理外部用户输入脚本时的首选安全模式。blackList 模式:黑名单策略,禁止特定方法,其他方法正常访问。适用于规则已经过审核、仅需防护高危 API 的场景。whiteList 模式:白名单策略,仅允许名单内的方法。安全性最高,但配置工作量最大。适用于严格执行安全规范的金融、政务场景。open 模式:完全开放,允许访问所有 Java API。危险等级最高,仅限于内部可信脚本的快速开发调试。// 白名单模式示例SetMemberwhite=newHashSet();white.add(Math.class.getMethod("abs",double.class));white.add(Math.class.getMethod("max",double.class,double.class));white.add(listClass.getMethod("size"));white.add(listClass.getMethod("get",int.class));Express4Runnerrunner=newExpress4Runner(InitOptions.builder().securityStrategy(QLSecurityStrategy.whiteList(white)).build());4.2.6 中文关键字支持这是 QLExpress 区别于其他所有方案的最显著特性。在中国企业的实际业务中,运营人员往往不具备编程能力,但又需要频繁调整促销规则。通过中文关键字,运营人员可以直接阅读和配置业务规则:runner.addOperatorWithAlias("如果","if",null);runner.addOperatorWithAlias("则","then",null);runner.addOperatorWithAlias("否则","else",null);runner.addOperatorWithAlias("而且","",null);runner.addOperatorWithAlias("或者","||",null);runner.addOperatorWithAlias("大于等于","=",null);runner.addOperatorWithAlias("小于","",null);// 运营人员可以直接写:如果(订单金额=1000而且 会员等级=="gold")则{返回 订单金额*0.8;}否则 如果(订单金额=500而且 会员等级=="silver")则{返回 订单金额*0.9;}否则{返回 订单金额;}这在中国企业的实际场景中具有巨大的实用价值。相比让运营人员学习=和这样的编程符号,直接用自然语言配置规则可以大幅降低沟通成本和错误率。4.2.7 语法校验(不执行,只检查语法合法性)CheckOptionscheckOptions=CheckOptions.builder().operatorCheckStrategy(OperatorCheckStrategy.whitelist(newHashSet(Arrays.asList("+","*","-","/","","","==","","||")))).disableFunctionCalls(false).build();runner.check("a 90 b 60",checkOptions);// 通过runner.check("System.exit(0)",checkOptions);// 抛出 QLSyntaxExceptioncheck()方法可以在不执行脚本的情况下验证语法合法性,并支持操作符白名单校验。这是防止恶意脚本的第一道防线——在将脚本存入数据库之前,先校验合法性。4.2.8 QLExpress 的主要局限不支持 Lambda 表达式:这是 QLExpress 与 AviatorScript 相比最大的功能短板。无法在脚本中直接编写闭包函数,意味着复杂的集合操作必须依赖预先注册的自定义函数,脚本的表达能力受到限制。集合操作抽象弱:没有 AviatorScript 那样的 Sequence 抽象(filter/map/reduce一体化),列表操作需要自己实现或依赖内置函数。没有解释器模式:不支持 Android 等非标准 JVM 环境。升级到 4.x 有迁移成本:API 与 3.x 不兼容,已有项目升级需要代码改造。4.3 MVEL 3.x — javac 编译路线MVEL(MVFLEX Expression Language)是一个混合动态/静态类型的表达式语言,特点是将表达式转译为 Java 源码,再通过 javac 内存编译执行。⚠️ 当前状态:MVEL 3.x 是全新重写的 alpha 版本,与旧的 MVEL 2.x 完全不兼容,API 和语法均有大幅变化。生产环境使用存在较大风险,建议等待正式版发布后再评估。MVEL 2.x 仍在 mvel2 分支 维护,但功能相对陈旧。MapString,Type?types=newHashMap();types.put("x",Type.type(int.class));types.put("y",Type.type(int.class));EvaluatorVoid,Integerevaluator=MVEL.Voidmap(Declaration.from(types))