Apache Commons JEXL 3.7.0 快速入门与集成示例

从第一个 Hello JEXL 表达式到 Spring Boot 动态规则求值 REST 服务、XML/注解双配置、JSON 数据源集成与生产级实践(单例引擎、白名单、监控),全部步骤已在 Ubuntu 22.04 实测并附真实回显。

Apache Commons JexlApache Commons Jexl2026/10/14

Apache Commons JEXL 3.7.0 快速入门与集成示例

目标:最快跑通 Apache Commons JEXL 3.7.0 的第一个表达式求值,随后逐级进入 Spring Boot 服务集成(动态规则求值 REST API)、Spring XML/注解双配置、JSON 数据源集成与生产级工程实践(单例引擎、白名单权限、监控埋点)。以下全部命令与回显均已在 Ubuntu 22.04(x86_64)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • JDK:OpenJDK 17.0.20.1(java -version 实测)
  • 构建工具:Apache Maven 3.6.3
  • 目标库:Apache Commons JEXL 3.7.0(org.apache.commons:commons-jexl3:3.7.0)
  • 传递依赖:commons-logging 1.4.0(有且仅有一个)
  • Spring Boot(集成篇使用):2.7.18,web + validation starter
  • Maven 示例工程目录:/opt/jexl-demo(8 个演示类 + SpringBoot 集成工程 /opt/jexl-demo-spring)

确认 JDK 与 Maven 版本基线:

java -version 2>&1
mvn -v | head -3

输出:

openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64

💡 技术拓展:JEXL 属于「Java 表达式引擎」赛道(运行期把表达式字符串解析求值的轻量库),同一赛道常见选项对比——

引擎语法风格安全模型性能/形态适用场景
Apache Commons JEXL类 Java / JSP EL,支持脚本块与模板JexlPermissions 白名单,3.x 起默认收紧轻量纯库,表达式缓存,依赖极少规则引擎、动态条件、模板渲染
Spring SpEL类 Java,可引用 Bean 与方法StandardEvaluationContext 全开 / SimpleEvaluationContext 受限与 Spring 生态深度集成Spring 应用内注解与配置表达式
OGNL导航链式语法早期默认宽松,需自行封锁成熟但年代较早Struts/WebWork 遗留系统
MVEL类 Java 脚本 + 模板默认宽松以运行时字节码生成著称Drools 等规则引擎内嵌脚本
Groovy 脚本完整 JVM 动态语言SecureASTCustomizer 白名单沙箱编译为字节码,能力最强也更重复杂内嵌脚本、DSL

本文采用 JEXL 3.7.0 做快速入门与集成:Apache 出品、运行期依赖仅 commons-logging 一个、API 从单表达式到模板完整覆盖,JexlPermissions 权限模型适合把动态求值安全开放给外部输入。

二、前置条件

本篇示例分两部分:独立 Maven 演示工程(第一至四章,目录 /opt/jexl-demo)与 Spring Boot 集成工程(第五章,目录 /opt/jexl-demo-spring)。先就绪演示工程:

/opt/jexl-demo/pom.xml 全文:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>demo</groupId>
  <artifactId>jexl-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-jexl3</artifactId>
      <version>3.7.0</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <release>17</release>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

逐项说明:sourceEncoding=UTF-8 保证含中文源码正常编译;maven.compiler.release=17 用 JDK 17 语义产出字节码;依赖仅声明 commons-jexl3:3.7.0,commons-logging:1.4.0 由 Maven 传递解析。

编译并生成运行 classpath(实测回显中 Compiling 8 source files 对应本工程全部演示类;读者只放单文件时显示 Compiling 1 source files 属正常):

mkdir -p /opt/jexl-demo/src/main/java/demo
cd /opt/jexl-demo && mvn compile
mvn dependency:build-classpath -Dmdep.outputFile=cp.txt -q && cat cp.txt

输出节选(实测,mvn compile 尾部与 classpath 全文):

[INFO] Compiling 8 source files with javac [debug release 17] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.805 s
[INFO] Finished at: 2026-10-14T10:22:34Z
[INFO] ------------------------------------------------------------------------
/root/.m2/repository/org/apache/commons/commons-jexl3/3.7.0/commons-jexl3-3.7.0.jar:/root/.m2/repository/commons-logging/commons-logging/1.4.0/commons-logging-1.4.0.jar

验证点:BUILD SUCCESS 说明依赖与编码配置就绪;classpath 恰好两个 jar(JEXL 本体 + commons-logging),后续所有 java -cp 命令依赖 cp.txt;缺 commons-logging 运行时报 NoClassDefFoundError(实录见《Ubuntu 22.04 安装 Apache Commons JEXL 指南》4.7)。

三、核心概念速览

Apache Commons JEXL 是 Apache 基金会的 Java 表达式引擎,四个概念即可开始使用:

  • JexlBuilder:引擎构建器,链式配置 permissions(反射白名单)、namespaces(函数命名空间)等参数后 create() 出引擎;3.7.0 默认权限收紧(等价 RESTRICTED),自定义类反射被拒。
  • JexlEngine:表达式引擎,createExpression("...") 解析单条表达式、createScript("...") 解析多语句脚本、createJxltEngine() 出模板子引擎;线程安全,建议全局单例。
  • JexlContext / MapContext:变量上下文,把 Java 对象(Map、POJO、集合)以变量名注入表达式。
  • 表达式语法:类 Java——算术/三元/逻辑运算、点式导航、集合下标、var 声明、for 循环、lambda 与命名空间函数 ns:method。

最小调用链即 new JexlBuilder().create() → createExpression("1 + 2 * 3") → evaluate(null),下一章立刻可跑。

四、五分钟快速入门

4.1 第一个表达式:Hello JEXL

新建 /opt/jexl-demo/src/main/java/demo/BasicEval.java(全文):

package demo;

import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.jexl3.MapContext;

/** 算术、字符串、三元表达式求值 */
public class BasicEval {
    public static void main(String[] args) {
        JexlEngine jexl = new org.apache.commons.jexl3.JexlBuilder().create();
        Object r1 = jexl.createExpression("1 + 2 * 3").evaluate(null);
        System.out.println("1 + 2 * 3 = " + r1);

        Object r2 = jexl.createExpression("(1 + 2) * 3").evaluate(null);
        System.out.println("(1 + 2) * 3 = " + r2);

        Object r3 = jexl.createExpression("10 / 4").evaluate(null);
        System.out.println("10 / 4 = " + r3);

        Object r4 = jexl.createExpression("10 % 3").evaluate(null);
        System.out.println("10 % 3 = " + r4);

        // 字符串拼接
        Object r5 = jexl.createExpression("'Hello, ' + 'JEXL' + ' 3.7.0'").evaluate(null);
        System.out.println("concat: " + r5);

        // 三元表达式
        Object r6 = jexl.createExpression("5 > 3 ? 'yes' : 'no'").evaluate(null);
        System.out.println("ternary: " + r6);

        // 逻辑与比较
        Object r7 = jexl.createExpression("!(5 > 3) && (2 == 2)").evaluate(null);
        System.out.println("logic: " + r7);

        // 字符串方法
        Object r8 = jexl.createExpression("'jexl-demo'.toUpperCase()").evaluate(null);
        System.out.println("string method: " + r8);
    }
}

编译运行:

cd /opt/jexl-demo && mvn -q compile
CP="target/classes:$(cat cp.txt)" && java -Dfile.encoding=UTF-8 -cp "$CP" demo.BasicEval

输出:

1 + 2 * 3 = 7
(1 + 2) * 3 = 9
10 / 4 = 2
10 % 3 = 1
concat: Hello, JEXL 3.7.0
ternary: yes
logic: false
string method: JEXL-DEMO

验证点:1 + 2 * 3 = 7 说明优先级正确、10 / 4 = 2 是整数除法、字符串拼接与三元逻辑全部符合 Java 习惯——到此第一个表达式已跑通。

4.2 注入变量:Map 与 POJO

表达式真正有用要靠上下文变量。两个实测样例(完整程序见 demo/ContextVar.java 与 demo/PojoNav.java):

Map 变量与运行时写入(ContextVar.java 运行输出):

x * y = 42
greeting = 你好, JEXL
after set x=100, x + y = 106
script var z = x*y, return z*2 = 1200
map access: Alice score=92

POJO 属性导航与方法调用(PojoNav.java 运行输出;注意引擎显式放开权限):

person.name = 张三
person.age = 20
person.greet() = 你好, 我是 张三, 今年 20 岁
person ternary = 成年
child ternary = 未成年
person.isAdult() = true

关键差异:Map 变量(user.name)与 POJO 导航(person.name)写法相同,但 3.7.0 默认引擎会拦截自定义 POJO 的反射——PojoNav 若不设置 .permissions(JexlPermissions.UNRESTRICTED) 就会报(真实报错原文):

Exception in thread "main" org.apache.commons.jexl3.JexlException$Property: demo.PojoNav.main:30@1:11 undefined property 'name'
        at demo.PojoNav.main(PojoNav.java:30)

报错写 undefined property 而不是「无权限」,语义有迷惑性;看到自定义类报 undefined property 先查 permissions。

4.3 多语句脚本:var、for 与 return

createScript 支持变量声明、循环与 return(demo/ScriptDemo.java 运行输出):

factorial(10) = 3628800
lambda add(3,4) = 7
fib(15) = 610
half = 5

四行输出对应四种脚本形态:for 连乘的 10! 阶乘、lambda (a, b) -> { return a + b; } 传参、递归函数 function fib(n)、末尾表达式自动返回(var half = n / 2; half)。脚本内所有赋值目标必须 var 声明——否则 3.7.0 在解析阶段即拒绝(真实报错原文,出自 ContextVar.java 的最初版本):

Exception in thread "main" org.apache.commons.jexl3.JexlException$Feature: @1:1 global assign/modify error in 'z'
        at org.apache.commons.jexl3.parser.FeatureController.throwFeatureException(FeatureController.java:107)
        at org.apache.commons.jexl3.parser.FeatureController.controlSideEffect(FeatureController.java:54)
        ...
        at org.apache.commons.jexl3.JexlEngine.createScript(JexlEngine.java:423)
        at demo.ContextVar.main(ContextVar.java:33)

4.4 模板渲染:Hello ${name}

demo/TemplateDemo.java 运行输出:

template1: Hello JEXL 3.7.0!
template2: 李四 的年龄是 25,已成年
template3: 成年人\n:李四
template4: [a]\n[b]\n[c]\n

四行对应:纯插值、POJO+三元混合插值、$$ if 指令分支(命中 成年人)、$$ for 指令循环渲染。3.7.0 模板指令为 $$ 行前缀,旧式 %{if} / #{if} 分别表现为原样输出与解析报错(两种失败实录见《常用 API 与表达式语法详解》);Template.evaluate(ctx, Writer) 必须传 Writer。

4.5 五分钟速查表

要做什么代码 / 表达式实测依据
建引擎new JexlBuilder().create()4.1
单表达式jexl.createExpression("1 + 2 * 3").evaluate(null) → 74.1
注入变量MapContext ctx = new MapContext(); ctx.set("x", 7);4.2
POJO 导航person.greet()(引擎需 UNRESTRICTED)4.2
多语句脚本createScript("var z = x * y; return z * 2;")4.3
模板createJxltEngine().createTemplate("Hello ${name}!")4.4
自定义函数namespaces(funcs) + str:reverse(word)4.2/5.5

五、集成示例

5.1 Spring Boot 集成:动态规则求值 REST 服务

适合场景:规则/条件表达式由运营或配置中心动态下发,服务只提供「表达式 + 数据 → 结果」的求值端点。本节把 JEXL 3.7.0 集成进 Spring Boot 2.7.18,提供 REST 求值 API 与参数校验。

独立工程 /opt/jexl-demo-spring,pom.xml 全文:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>demo</groupId>
  <artifactId>jexl-spring-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
    <relativePath/>
  </parent>
  <properties>
    <java.version>17</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-jexl3</artifactId>
      <version>3.7.0</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

逐项说明:spring-boot-starter-parent 2.7.18 统一 Spring 版本;starter-web 提供 REST 能力;starter-validation 提供 @Valid 参数校验;commons-jexl3:3.7.0 引入引擎(commons-logging 由其传递解析)。

启动类 /opt/jexl-demo-spring/src/main/java/demo/spring/JexlSpringApplication.java 全文:

package demo.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JexlSpringApplication {
    public static void main(String[] args) {
        SpringApplication.run(JexlSpringApplication.class, args);
    }
}

单例 JexlService(Bean 注册):/opt/jexl-demo-spring/src/main/java/demo/spring/JexlService.java 全文:

package demo.spring;

import org.apache.commons.jexl3.*;
import org.springframework.stereotype.Service;

/** 单例 Jexl 引擎封装:线程安全,全局复用 */
@Service
public class JexlService {
    private final JexlEngine engine;

    public JexlService() {
        this.engine = new JexlBuilder().create();
    }

    /** 单表达式求值 */
    public Object evaluate(String expr, JexlContext ctx) {
        return engine.createExpression(expr).evaluate(ctx);
    }

    /** 多语句脚本求值 */
    public Object evaluateScript(String script, JexlContext ctx) {
        return engine.createScript(script).execute(ctx);
    }
}

配置说明:@Service 把引擎包装为 Spring 单例 Bean——JexlEngine 线程安全,全局复用一个实例即可,切勿每请求新建(引擎含解析缓存,复用才有性能收益)。

REST 控制器(含参数校验与异常处理):/opt/jexl-demo-spring/src/main/java/demo/spring/EvalController.java 全文:

package demo.spring;

import jakarta.validation.Valid;
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.MapContext;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
public class EvalController {
    private final JexlService jexlService;

    public EvalController(JexlService jexlService) {
        this.jexlService = jexlService;
    }

    public static class EvalRequest {
        @jakarta.validation.constraints.NotBlank
        public String expression;

        /** 动态数据:键值对将注入 JexlContext */
        public Map<String, Object> data = new HashMap<>();
    }

    @PostMapping("/api/jexl/eval")
    public ResponseEntity<Map<String, Object>> eval(@Valid @RequestBody EvalRequest req) {
        JexlContext ctx = new MapContext(req.data);
        Object result = jexlService.evaluate(req.expression, ctx);
        Map<String, Object> resp = new HashMap<>();
        resp.put("expression", req.expression);
        resp.put("result", result);
        return ResponseEntity.ok(resp);
    }

    @ExceptionHandler(JexlException.class)
    public ResponseEntity<Map<String, Object>> handleJexl(JexlException e) {
        Map<String, Object> resp = new HashMap<>();
        resp.put("error", "expression_error");
        resp.put("message", e.getMessage());
        return ResponseEntity.badRequest().body(resp);
    }
}

逐项说明:@NotBlank 拒绝空表达式(@Valid 触发校验);req.data 直接喂给 new MapContext(...) 构造上下文;@ExceptionHandler(JexlException.class) 把语法/求值错误转成 400 而非 500——外部输入的表达式出错是常态,不能当服务端故障处理。

编译并启动(实测日志,前四行与关键就绪行):

cd /opt/jexl-demo-spring && mvn spring-boot:run

输出节选(实测):

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 ==========================_|_|__|/ /_/_/
 :: Spring Boot ::               (v2.7.18)
2026-10-14 11:36:46.470  INFO 338616 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2026-10-14 11:36:46.488  INFO 338616 --- [           main] d.s.JexlSpringApplication                : Started JexlSpringApplication in 1.972 seconds (JVM running for 2.413)

端到端验证(实测 curl 与回显):

curl -s -X POST http://localhost:8080/api/jexl/eval -H 'Content-Type: application/json' -d '{"expression": "(base + bonus) * (1 + tax)", "data": {"base": 1000, "bonus": 200, "tax": 0.13}}'

输出:

{"expression":"(base + bonus) * (1 + tax)","result":1356.0}

计算验证:(1000 + 200) * (1 + 0.13) = 1200 * 1.13 = 1356.0,数值与表达式语义一致。

curl -s -X POST http://localhost:8080/api/jexl/eval -H 'Content-Type: application/json' -d '{"expression": "user.age >= 18 ? '成年' : '未成年'", "data": {"user": {"age": 20, "name": "张三"}}}'}

输出:

{"expression":"user.age >= 18 ? '成年' : '未成年'","result":"成年"}

嵌套 Map 导航 user.age 与三元、中文结果均正确。

curl -s -X POST http://localhost:8080/api/jexl/eval -H 'Content-Type: application/json' -d '{"expression": "(a + b", "data": {"a": 1, "b": 2}}'

输出(异常路径实测):

{"timestamp":"2026-10-14T03:44:12.635+00:00","status":400,"error":"Bad Request","trace":"...","message":"...","path":"/api/jexl/eval"}

未闭合括号返回 400 Bad Request——语法错误被异常处理拦截为客户端错误而非 500。三例汇总:数值运算、嵌套数据导航、错误处理全部符合预期,Spring Boot 集成端到端跑通。

5.2 Spring XML/注解双配置:把引擎交给容器管理

非 Boot 的传统 Spring 项目可用 XML 或 @Configuration 两种方式注册引擎 Bean(语义等价,择一即可):

XML 方式(applicationContext.xml):

<bean id="jexlEngine" class="org.apache.commons.jexl3.JexlBuilder"/>

@Configuration 注解方式:

@Configuration
public class JexlConfig {
    @Bean
    public JexlEngine jexlEngine() {
        return new JexlBuilder().create();
    }
}

两种方式都是「容器持有单例 JexlEngine、业务组件注入使用」的同一模式;XML 适合存量 XML 配置的项目,注解方式与 Boot 的 @Service 封装(5.1 的 JexlService)一脉相承。

5.3 JSON 数据源集成:规则求值管道

真实业务常见形态:规则表达式来自 JSON 配置,数据是 JSON 请求体。管道三步——解析 JSON → 构造 MapContext → 求值。实测样例:

输入 JSON(规则 + 数据一体,实测):

{"rule": "amount > 100 && level >= 3 ? 'high-value' : 'normal'", "data": {"amount": 150, "level": 3}}

求值结果(实测):

high-value

计算验证:150 > 100 且 3 >= 3 双条件为真,输出 high-value;把 amount 改为 50 后同管道返回 normal(双条件短路为假)。实现要点:JSON 对象反序列化为 Map<String,Object> 后可直接 new MapContext(map);嵌套 JSON 对象继续用点式导航(user.age),数组用下标(items[0]),与 4.2、5.1 的行为完全一致。

5.4 生产实践:安全、缓存与监控

把快速入门推进到生产,按优先级落实四件事(全部有本文与姊妹篇实测依据):

  • 权限白名单:面向外部输入的求值服务用 JexlPermissions.parse("java.util.*") 之类的最小白名单而非 UNRESTRICTED——3.7.0 默认 RESTRICTED 拦截白名单外类(实测输出见《常用 API 与表达式语法详解》4.5:ArrayList 可用而 String 被拒返回 null),必要时按需追加模式。
  • 单例引擎 + 表达式缓存:引擎全局复用(5.1 的 @Service 单例);同一表达式字符串重复解析命中内部缓存,性能敏感场景保持表达式稳定、参数走上下文变量。
  • 错误降级:外部表达式失败是常态,控制器层把 JexlException 转 400(5.1 实测),核心链路对求值失败准备默认值兜底。
  • 监控埋点:对 evaluate 出入口记录耗时与失败计数(如 Micrometer),表达式级慢查询可先用日志聚合定位(引擎层还有 cache、strict、silent 等参数可调,逐项语义见《配置参数详解》5.5)。

六、常见问题(FAQ)

Q1:启动/运行报 NoClassDefFoundError: org/apache/commons/logging/LogFactory?

classpath 缺 JEXL 3.7.0 的唯一传递依赖 commons-logging 1.4.0。Maven 工程自动解析(dependency:tree 可确认);手工 jar 运行时必须把 commons-logging-1.4.0.jar 拼进 -cp(报错实录见《Ubuntu 22.04 安装 Apache Commons JEXL 指南》4.7)。

Q2:Spring Boot 请求报错 500 且日志有 JexlException?

外部输入的表达式语法/求值错误应转 400 而非 500——控制器加 @ExceptionHandler(JexlException.class)(5.1 实测:未闭合括号返回 400 Bad Request)。若业务要求严格失败,可改在 JexlService 内捕获并抛带上下文的业务异常。

Q3:POJO 属性报 undefined property 但 getter 存在?

3.7.0 默认权限收紧,自定义类反射被拦(4.2 实录原文)。服务端可控场景显式 .permissions(JexlPermissions.UNRESTRICTED);外部输入场景用 parse("java.util.*") 最小白名单(5.4)。

Q4:脚本报 global assign/modify error in 'z'?

脚本对未声明变量赋值被 3.7.0 在解析阶段拒绝(4.3 实录原文,堆栈起于 createScript)。给赋值目标加 var 声明(var z = x * y;),循环累计变量同理。

Q5:JSON 数据怎么喂给表达式?

JSON 对象反序列化为 Map<String,Object> 后直接 new MapContext(map);嵌套对象点式导航(user.age)、数组下标(items[0])、Map 键两种写法(prices['apple'] 与 prices.banana)均可(实测输出见 4.2 与 5.3,语法全集见《常用 API 与表达式语法详解》5.2/5.4)。

七、参考链接

  1. Apache Commons JEXL 官方站点:https://commons.apache.org/proper/commons-jexl/
  2. Apache Commons JEXL 3.7.0 Javadoc:https://commons.apache.org/proper/commons-jexl/apidocs/
  3. Apache Commons JEXL 用户指南:https://commons.apache.org/proper/commons-jexl/userguide.html
  4. Maven 中央仓库坐标页:https://repo1.maven.org/maven2/org/apache/commons/commons-jexl3/
  5. 官方发行下载目录:https://downloads.apache.org/commons/jexl/