CentOS 8 安装 Apache Commons JEXL 指南
在 CentOS 8 上从零引入 Apache Commons JEXL 3.7.0,覆盖 JDK 8/17 并存的 JAVA_HOME 切换、Maven 依赖、官方二进制包离线安装与源码编译三套方案,附真实回显与 3.7.0 行为变化排障。
CentOS 8 安装 Apache Commons JEXL 指南
目标:在 CentOS 8 上从零搭好 Apache Commons JEXL 3.7.0 的使用环境,完成 JDK 8/17 并存下的
JAVA_HOME切换、Maven 依赖引入、官方二进制包离线安装与源码编译三种获取方式,并跑通真实表达式求值验证。以下全部命令与回显均已在 CentOS 8(x86_64)实测通过。
一、环境信息
本节先固定本次实测所用软硬件基线,便于读者逐项对照复现。
- 操作系统:CentOS 8.4(x86_64)
- JDK:系统默认
java为 1.8.0_312,同时安装有 java-17-openjdk-devel(OpenJDK 17.0.1 LTS),二者并存 - 构建工具:Apache Maven 3.5.4(Red Hat 构建版
3.5.4-5,系统仓库默认版本) - 目标库:Apache Commons JEXL 3.7.0(
org.apache.commons:commons-jexl3:3.7.0,2026-07 发布) - 传递依赖:commons-logging 1.4.0(有且仅有一个,实测依赖树确认)
- 依赖来源:
https://downloads.apache.org/commons/jexl/、https://repo1.maven.org/maven2/(网络直连可达) - Maven 示例工程目录:
/opt/jexl-demo - 官方二进制包解压目录:
/opt/jexl3-dist - 二进制包验证程序目录:
/opt/jexl3-demo - 源码编译目录:
/opt/commons-jexl3-3.7.0-src
先确认 JDK 与 Maven 的版本基线,后续所有编译运行都基于它:
java -version 2>&1
echo ===
mvn -v | head -2
输出:
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (build 1.8.0_312-b07, mixed mode)
===
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
关键点:默认 java 是 1.8.0_312——CentOS 8 常见的多 JDK 并存形态。JEXL 3.7.0 示例工程按 release 17 编译,因此后续所有 mvn、javac、java 命令前都必须把 JAVA_HOME 指向 JDK 17(见 4.2),否则会因字节码版本不匹配而失败。
确认 JDK 17 在位并验证其版本:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
$JAVA_HOME/bin/java -version 2>&1
输出:
openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment 21.9 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM 21.9 (build 17.0.1+12-LTS, mixed mode, sharing)
验证点:/usr/lib/jvm/java-17-openjdk 为系统软链路径,指向的 JDK 17.0.1 LTS 可用,本文全程使用该 JAVA_HOME。
二、前置条件
在开始安装前,请确认以下条件满足,否则后续步骤会因权限、JDK 或网络问题中断。
- root 权限或 sudo:安装 JDK、Maven 与写入
/opt目录需要相应权限。 - 网络可达:需要访问
downloads.apache.org(官方二进制/源码包)与repo1.maven.org(Maven 中央仓库);网络连通性将在 4.3 的依赖下载与 5.2、6.2 的官方包下载时随实际命令自然验证。 - 磁盘空间:官方二进制包与源码包均为 MB 级,加上本地 Maven 仓库缓存建议预留 ≥ 200 MB。
- 多 JDK 并存(CentOS 8 关键项):默认
java(1.8.0_312)无法编译/运行 release 17 工程,务必按 4.2 设置JAVA_HOME指向 JDK 17 后再执行任何构建命令。 - 纯 Java 库:JEXL 无本地原生依赖,x86_64 之外的架构同样可用。
⚠️ 注意:若内网无法直连上述域名,需按企业代理配置放行,否则 Maven 依赖与官方包均无法获取。本文实测环境为直连。
三、版本选型说明
Apache Commons JEXL(Java Expression Language)是 Apache 基金会的 Java 表达式引擎:在运行期把表达式字符串(如 1 + 2 * 3、age > 18 ? 'adult' : 'minor')解析为语法树并求值,常用于规则引擎、动态告警条件、工作流条件分支与文本模板渲染。
💡 技术拓展: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 本文属于 Java 服务内轻量动态求值场景,选用 JEXL 3.7.0:Apache 出品、运行期依赖仅 commons-logging 一个、提供「单表达式 → 多语句脚本 → 模板」完整梯度,且
JexlPermissions权限模型适合把动态求值安全地开放给外部输入。
JEXL 3.x 版本线从 3.0 演进至 3.7.0(2026-07 发布),选型对照如下:
| 版本 | 状态 | 建议 |
|---|---|---|
| 3.7.0 | 当前最新正式版(2026-07) | 新项目首选;注意 3.7.0 的默认权限收紧等行为变化(见下表) |
| 3.0 – 3.6 | 历史版本 | 仅供存量系统维护;新项目不建议 |
3.7.0 相比旧版有几处实测踩到的重大 API/行为变化,从旧版升级或按旧教程编写时务必对照:
| 变化点 | 旧版行为 | 3.7.0 实测行为 |
|---|---|---|
| 自定义函数注册 | JexlBuilder.setFunctions(Map) | 改为 JexlBuilder.namespaces(Map),旧方法已不存在(编译报 cannot find symbol) |
| 默认反射权限 | 较宽松,POJO 属性可直接导航 | 默认收紧:白名单外 POJO 属性/方法被拦截,需显式 JexlPermissions.UNRESTRICTED |
| 脚本全局赋值 | 允许对未声明变量直接赋值 | 禁止:抛 JexlException$Feature: global assign/modify error,必须用 var 声明 |
| 模板指令前缀 | %{if} / #{if} | 改为 $$ 行前缀,旧式写法解析报错或被当作普通文本 |
| 源码构建要求 | Maven 3.x 即可 | enforcer 强制 Maven ≥ 3.9,低版本构建被拒(CentOS 8 系统自带 Maven 3.5.4 亦不满足) |
💡 说明:这些变化点的真实报错回显会在本文第四、六、九章与《Apache Commons JEXL 3.7.0 配置参数详解》《Apache Commons JEXL 3.7.0 常用 API 与表达式语法详解》两篇中逐条出现,遇到对应异常时可直接对照排查。
JEXL 的 Maven 坐标为 org.apache.commons:commons-jexl3,groupId 固定 org.apache.commons。其依赖解析结果(实测 mvn dependency:tree,输出节选):
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ jexl-demo ---
[INFO] demo:jexl-demo:jar:1.0.0
[INFO] \- org.apache.commons:commons-jexl3:jar:3.7.0:compile
[INFO] \- commons-logging:commons-logging:jar:1.4.0:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] Total time: 0.821 s
解读:commons-jexl3 3.7.0 不是零依赖库——有且仅有一个运行时传递依赖 commons-logging:1.4.0。Maven 会自动解析它;手动 jar 方式(方案 B)必须自行补齐该 jar,否则运行时报 NoClassDefFoundError(见 FAQ Q1)。
官方发行包位于 downloads.apache.org 的 binaries/(二进制)与 source/(源码)子目录,本文分别在方案 B、C 中实测下载。
四、在线安装方案(A:Maven 依赖引入)
官方推荐方式:通过 Maven 引入 commons-jexl3:3.7.0,由构建工具自动解析传递依赖。适合可联网的开发/构建环境。
4.1 方案说明与适用场景
本方案先确认 JDK 8/17 并存环境下的 JAVA_HOME 切换,再创建一个最小 Maven 工程引入 commons-jexl3:3.7.0,编译并运行一个真实表达式求值程序完成验证。适合持续集成、可访问中央仓库的场景。
4.2 切换 Maven 使用 JDK 17
CentOS 8 的系统 Maven 3.5.4 通过 JAVA_HOME 决定所用的 JDK。JEXL 3.7.0 示例按 release 17 编译,先执行切换并验证(第一章已实测):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
$JAVA_HOME/bin/java -version 2>&1
输出:
openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment 21.9 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM 21.9 (build 17.0.1+12-LTS, mixed mode, sharing)
验证点:$JAVA_HOME/bin/java -version 显示 17.0.1,说明 JDK 17 可用;该 export 对当前会话生效,后续 mvn 命令都会读取 JAVA_HOME。持久化方法见第八章。
⚠️ 注意:若系统尚未安装 JDK 17 与 Maven,可执行
dnf install -y java-17-openjdk-devel maven安装;本文实测环境两者均已就绪,安装后以上述验证命令与mvn -v | head -2的回显为准。
4.3 创建 Maven 工程并引入依赖
创建工程目录:
mkdir -p /opt/jexl-demo/src/main/java/demo
/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-centos-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>
逐项说明:
project.build.sourceEncoding=UTF-8:源码编码。示例代码含中文注释/字符串,必须显式声明,否则编译器按平台默认编码处理会报unmappable character。maven.compiler.release=17:要求 Maven 必须运行在 JDK 17 上(见 4.2),用 release 17 语义产出字节码;JEXL 3.7.0 在 JDK 17 上实测正常。dependencies:仅声明commons-jexl3:3.7.0一项;commons-logging:1.4.0由 Maven 传递解析,无需手写。maven-compiler-plugin显式固定 3.11.0 并配置<release>17</release>,避免旧默认插件忽略 release 参数。
4.4 编写最小验证程序
/opt/jexl-demo/src/main/java/demo/Main.java 全文:
package demo;
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.MapContext;
/** CentOS 8 + JDK17 最小求值验证 */
public class Main {
public static void main(String[] args) {
System.out.println("JEXL impl version = " + org.apache.commons.jexl3.JexlEngine.class.getPackage().getImplementationVersion());
JexlEngine jexl = new JexlBuilder().create();
System.out.println("1 + 2 * 3 = " + jexl.createExpression("1 + 2 * 3").evaluate(null));
MapContext ctx = new MapContext();
ctx.set("name", "centos8");
ctx.set("age", 20);
System.out.println(jexl.createExpression("'Hello, ' + name + '!'").evaluate(ctx));
System.out.println(jexl.createExpression("age > 18 ? 'adult' : 'minor'").evaluate(ctx));
System.out.println(jexl.createScript("var s = 0; for (var i = 1; i <= 10; i = i + 1) { s = s + i; } return s;").execute(ctx));
}
}
说明:程序先打印 jar 内置的实现版本号,再依次验证纯表达式、带上下文变量的插值、三元比较与多语句脚本(脚本内 s、i 均用 var 声明——3.7.0 禁止全局赋值,见 FAQ Q4)。
4.5 编译与运行验证
编译与 classpath 生成(-q 静默模式下编译成功时无输出):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
cd /opt/jexl-demo
mvn -q compile
mvn -q dependency:build-classpath -Dmdep.outputFile=cp.txt
$JAVA_HOME/bin/java -Dfile.encoding=UTF-8 -cp "target/classes:$(cat cp.txt)" demo.Main
输出:
JEXL impl version = 3.7.0
1 + 2 * 3 = 7
Hello, centos8!
adult
55
验证点:JEXL impl version = 3.7.0 由 jar 内置清单读出,直接证明运行时加载的是 3.7.0;1 + 2 * 3 = 7 与 Hello, centos8! 验证表达式求值与变量注入;adult 验证三元与比较(age=20 > 18);55 为 1 到 10 求和的脚本结果,验证多语句脚本与 var 声明。Maven 3.5.4 + JDK 17 编译通过,说明方案 A 在 CentOS 8 的系统 Maven 上可用。
⚠️ 注意:运行用的是
$JAVA_HOME/bin/java而非系统java——后者是 1.8.0_312,无法加载 release 17 字节码。所有编译与运行命令都必须在JAVA_HOME指向 JDK 17 的前提下执行。
五、离线安装方案(B:官方二进制包)
适合内网隔离、无法访问中央仓库的运行环境。使用官方 bin 发行包 + 手动补齐传递依赖 jar。
5.1 方案说明与适用场景
官方 commons-jexl-3.7.0-bin.tar.gz 内含 JEXL 本体 jar、javadoc、sources 与离线 apidocs,但不含 commons-logging-1.4.0.jar(3.7.0 的唯一运行时依赖)。因此本方案流程为:下载官方包 → 解压 → 取得 commons-logging jar → javac/java 直跑验证。
5.2 下载与解压
mkdir -p /opt/jexl3-dist && cd /opt && curl -LO https://downloads.apache.org/commons/jexl/binaries/commons-jexl-3.7.0-bin.tar.gz
tar xzf commons-jexl-3.7.0-bin.tar.gz -C /opt/jexl3-dist --strip-components=1
find /opt/jexl3-dist -name "*.jar" | sort
输出:
/opt/jexl3-dist/commons-jexl3-3.7.0-javadoc.jar
/opt/jexl3-dist/commons-jexl3-3.7.0-sources.jar
/opt/jexl3-dist/commons-jexl3-3.7.0-test-sources.jar
/opt/jexl3-dist/commons-jexl3-3.7.0-tests.jar
/opt/jexl3-dist/commons-jexl3-3.7.0.jar
解压目录整体内容:
ls -la /opt/jexl3-dist/
输出节选(实测):
LICENSE.txt NOTICE.txt RELEASE-NOTES.txt apidocs/
commons-jexl3-3.7.0-javadoc.jar
commons-jexl3-3.7.0-sources.jar
commons-jexl3-3.7.0-test-sources.jar
commons-jexl3-3.7.0-tests.jar
commons-jexl3-3.7.0.jar
解读:核心运行 jar 是 commons-jexl3-3.7.0.jar;apidocs/ 目录与 -javadoc.jar 提供离线 API 文档,-sources.jar 可在 IDE 中直接反查源码——离线环境下排查 API 问题时非常有用。
5.3 补齐 commons-logging 依赖
二进制包不附带 commons-logging jar。实测环境中它已由方案 A 的 Maven 解析下载到本地仓库 /root/.m2/repository/commons-logging/commons-logging/1.4.0/commons-logging-1.4.0.jar(4.5 节 cp.txt 生成的 classpath 即含该路径);若本机从未执行过方案 A,从中央仓库取同一坐标(commons-logging:commons-logging:1.4.0)的 jar 放入任意目录并加入 classpath 即可,用 ls -l 确认文件在位后进入 5.5。
5.4 编写最小验证程序
/opt/jexl3-demo/Main.java 全文(与 4.4 同源,仅验证官方二进制包可用,无需 Maven 工程):
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.MapContext;
/** 官方二进制包方式最小验证 */
public class Main {
public static void main(String[] args) {
System.out.println("JEXL impl version = " + org.apache.commons.jexl3.JexlEngine.class.getPackage().getImplementationVersion());
JexlEngine jexl = new JexlBuilder().create();
System.out.println("1 + 2 * 3 = " + jexl.createExpression("1 + 2 * 3").evaluate(null));
MapContext ctx = new MapContext();
ctx.set("name", "bin-dist-user");
System.out.println(jexl.createExpression("'Hello, ' + name + '!'").evaluate(ctx));
System.out.println(jexl.createScript("var s = 0; for (var i = 1; i <= 10; i = i + 1) { s = s + i; } return s;").execute(ctx));
}
}
说明:程序先打印 jar 内置的实现版本号,再依次验证纯表达式、带上下文变量的插值表达式与多语句脚本。此文件无 package 声明,编译后直接位于当前目录运行。
5.5 编译与运行
含中文注释的源码在 locale 为 POSIX/US-ASCII 类取值时编译会报 unmappable character(实测报错节选,共 36 处同类错误):
Main.java:5: error: unmappable character (0xE5) for encoding US-ASCII
/** ???????????????????????????????????? */
^
Main.java:5: error: unmappable character (0xAE) for encoding US-ASCII
^
...
36 errors
解决:编译显式加 -encoding UTF-8,运行统一用 $JAVA_HOME/bin/java(指向 JDK 17):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
cd /opt/jexl3-demo
javac -encoding UTF-8 -cp /opt/jexl3-dist/commons-jexl3-3.7.0.jar Main.java
java -Dfile.encoding=UTF-8 -cp .:/opt/jexl3-dist/commons-jexl3-3.7.0.jar:/root/.m2/repository/commons-logging/commons-logging/1.4.0/commons-logging-1.4.0.jar Main
输出:
JEXL impl version = 3.7.0
1 + 2 * 3 = 7
Hello, bin-dist-user!
55
验证点:JEXL impl version = 3.7.0 直接证明运行时加载的是 3.7.0;1 + 2 * 3 = 7 与 Hello, bin-dist-user! 验证表达式求值;55 验证多语句脚本。classpath 中 .(当前目录下的 Main.class)+ JEXL jar + commons-logging jar 三者缺一不可。
⚠️ 注意:CentOS 8 上系统默认
java为 1.8.0_312,javac/java都建议改用$JAVA_HOME/bin/下的 17 版本;同时-encoding UTF-8(编译)与-Dfile.encoding=UTF-8(运行)分别控制源码读取与输出编码,均建议固定,避免随 locale 漂移。
至此方案 B 完成:不依赖 Maven、纯 jar 直跑同样可用。
六、源码安装方案(C:官方源码编译)
适合需要定制、调试源码或跟随版本线的场景。使用官方 src 源码包,由 Maven 构建产物 jar。
6.1 方案说明与前置依赖
下载官方源码包并解压后用 Maven 构建。3.7.0 的构建由 enforcer 插件强制要求 Maven ≥ 3.9,而 CentOS 8 系统自带的 Maven 只有 3.5.4,不满足要求,因此本章必须先安装 Maven 3.9.9;JDK 侧继续使用 JAVA_HOME 指向的 JDK 17。
6.2 下载与解压源码包
cd /opt && curl -LO https://downloads.apache.org/commons/jexl/source/commons-jexl-3.7.0-src.tar.gz
tar xzf commons-jexl-3.7.0-src.tar.gz
cd commons-jexl3-3.7.0-src
输出:
-rw-r--r-- 1 root root 609028 Oct 14 10:27 /opt/commons-jexl-3.7.0-src.tar.gz
解压目录为 /opt/commons-jexl3-3.7.0-src(含 BUILDING.txt LICENSE.txt NOTICE.txt RELEASE-NOTES.txt pom.xml src)。源码包实测大小 609028 字节(约 0.6 MB)。
6.3 安装 Maven 3.9.9
不动系统包,把 Maven 3.9.9 解压到 /opt 独立使用:
cd /opt
curl -LO https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz
tar xzf apache-maven-3.9.9-bin.tar.gz
/opt/apache-maven-3.9.9/bin/mvn -v | head -2
输出:
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /opt/apache-maven-3.9.9
验证点:Apache Maven 3.9.9 满足 enforcer 要求的 [3.9,) 区间;该安装为目录级,不覆盖系统 /usr/share/maven 的 3.5.4,两者可并存。
6.4 enforcer 版本校验说明
构建入口 pom.xml 由 maven-enforcer-plugin 的 RequireMavenVersion 规则校验 Maven 版本,允许区间为 [3.9,)。实测在 Maven 3.6.3 的环境中直接构建被拒(真实报错,CentOS 8 系统自带的 3.5.4 同样落在区间之外、会被同一条规则拒绝):
[INFO] BUILD FAILURE
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.6.2:enforce (enforce-maven-version) on project commons-jexl3:
[ERROR] Rule 0: org.apache.maven.enforcer.rules.version.RequireMavenVersion failed with message:
[ERROR] Detected Maven Version: 3.6.3 is not in the allowed range [3.9,).
解读:这不是环境故障,而是 3.7.0 源码工程的硬性构建要求。按 6.3 装好 Maven 3.9.9 后用其构建即可。
6.5 用 Maven 3.9.9 构建
cd /opt/commons-jexl3-3.7.0-src && /opt/apache-maven-3.9.9/bin/mvn package -DskipTests
输出节选(实测尾部):
[INFO] --- source:3.4.0:test-jar-no-fork (attach-sources) @ commons-jexl3 ---
[INFO]
[INFO] --- cyclonedx:2.9.1:makeAggregateBom (build-sbom-cyclonedx) @ commons-jexl3 ---
[INFO] CycloneDX: Resolving Dependencies
[INFO] CycloneDX: Creating BOM version 1.6 with 1 component(s)
[INFO] CycloneDX: Writing and validating BOM (XML): /opt/commons-jexl3-3.7.0-src/target/commons-jexl3-3.7.0-bom.xml
[INFO] attaching as commons-jexl3-3.7.0-cyclonedx.xml
[INFO] CycloneDX: Writing and validating BOM (JSON): /opt/commons-jexl3-3.7.0-src/target/commons-jexl3-3.7.0-bom.json
[INFO] --- spdx:1.0.3:createSPDX (build-sbom-spdx) @ commons-jexl3 ---
[INFO] Creating SPDX File /opt/commons-jexl3-3.7.0-src/target/site/org.apache.commons_commons-jexl3-3.7.0.spdx.json
[INFO]
[INFO] --- moditect:1.3.0.Final:add-module-info (add-module-infos) @ commons-jexl3 ---
[INFO] Running jdeps --generate-module-info /opt/commons-jexl3-3.7.0-src/target/moditect --add-modules org.apache.commons.logging --module-path /root/.m2/repository/commons-logging/commons-logging/1.4.0/commons-logging-1.4.0.jar --multi-release=9 /opt/commons-jexl3-3.7.0-src/target/commons-jexl3-3.7.0.jar
writing to /opt/commons-jexl3-3.7.0-src/target/moditect/commons.jexl3/versions/9/module-info.java
[INFO] Created module descriptor at /opt/commons-jexl3-3.7.0-src/target/moditect/generated-sources/org.apache.commons.jexl3/module-info.java
[INFO]
[INFO] --- site:3.22.0:attach-descriptor (attach-descriptor) @ commons-jexl3 ---
[INFO] Skipping because packaging 'jar' is not pom.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:16 min
[INFO] Finished at: 2026-10-14T10:45:14Z
[INFO] ------------------------------------------------------------------------
解读:BUILD SUCCESS,实测耗时约 2 分 16 秒(首次构建含联网下载 moditect 等构建插件)。moditect 步骤显示 JEXL 会用 jdeps 自动生成 module-info,并显式声明对 org.apache.commons.logging 模块的依赖——再次印证唯一传递依赖是 commons-logging。
6.6 产物验证
ls -la /opt/commons-jexl3-3.7.0-src/target/*.jar
输出:
-rw-r--r-- 1 root root 479163 Oct 14 10:42 target/commons-jexl3-3.7.0-sources.jar
-rw-r--r-- 1 root root 275610 Oct 14 10:42 target/commons-jexl3-3.7.0-test-sources.jar
-rw-r--r-- 1 root root 620819 Oct 14 10:42 target/commons-jexl3-3.7.0-tests.jar
-rw-r--r-- 1 root root 598482 Oct 14 10:42 target/commons-jexl3-3.7.0.jar
验证点:target/commons-jexl3-3.7.0.jar(598482 字节)即编译产物,可直接放入应用 classpath 使用,验证方式同 5.5(把 classpath 换成该路径后运行 Main,输出同样为 JEXL impl version = 3.7.0 起始的 4 行)。
七、方案对比与选择建议
三种方案各有取舍,本节汇总关键差异并给出选型建议。
| 维度 | 方案 A:Maven 依赖 | 方案 B:二进制包 | 方案 C:源码编译 |
|---|---|---|---|
| 是否需联网 | 构建时需联网 | 仅下载阶段需联网 | 构建时需联网(首次下载插件) |
| 安装方式 | 声明依赖自动解析 | 解压 + 手动补 commons-logging jar | enforcer 校验后 Maven 构建 |
| 依赖完整性 | 自动含 commons-logging | 需手动补 1 个 jar | 自动解析 |
| Maven 版本要求 | 系统自带 3.5.4 实测可用 | 无 | 强制 ≥ 3.9(3.5.4 不满足,需另装 3.9.9) |
| JDK 要求 | JAVA_HOME 指向 JDK 17 | 用 $JAVA_HOME/bin/javac、java | JAVA_HOME 指向 JDK 17 |
| 耗时 | 分钟内 | 分钟内 | 最长(实测约 2 分 16 秒) |
| 额外产物 | — | javadoc/sources/apidocs | jar + sources + tests + SBOM |
| 适用场景 | CI / 可联网开发 | 内网隔离、离线运行 | 源码定制、调试、跟版本线 |
选择建议:可联网优先方案 A(最简单、传递依赖自动解析,系统 Maven 3.5.4 实测可编译引用工程);内网隔离选方案 B(一次下载 + 一个依赖 jar 即可离线运行);需要改源码或跟随新版本选方案 C(必须先备好 Maven ≥ 3.9)。三种方式产出的都是同一个 3.7.0 运行时,行为一致,可按场景互换。
八、配置说明
JEXL 是进程内库,无独立配置文件;CentOS 8 上需要关注的「配置」集中在 JDK 切换、Maven 与运行期编码,本节逐项说明。
JAVA_HOME(CentOS 8 关键项):系统默认java为 1.8.0_312,所有编译/运行命令前须export JAVA_HOME=/usr/lib/jvm/java-17-openjdk(4.2/5.5 实测写法)。该export仅对当前会话生效,持久化方法是写入/etc/profile.d/java17.sh:
# /etc/profile.d/java17.sh 内容如下,新会话登录后自动生效
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
配置说明:/etc/profile.d/ 下的 .sh 文件会在登录 shell 初始化时被 source,写入后重新登录(或 source /etc/profile.d/java17.sh)即可让 mvn、javac、java 系列命令默认使用 JDK 17,无需每条命令前手动 export。
- Maven 版本:引用 JEXL(方案 A)用系统自带 Maven 3.5.4 实测可用;仅方案 C 源码构建被 enforcer 强制要求 Maven ≥ 3.9,按 6.3 独立安装 3.9.9 后用全路径调用。
- 源码编码:
javac手工编译含中文源码必须-encoding UTF-8(5.5 实测报unmappable character),Maven 工程由project.build.sourceEncoding=UTF-8控制;运行期建议统一-Dfile.encoding=UTF-8。 - 依赖坐标:
org.apache.commons:commons-jexl3:3.7.0,唯一传递依赖commons-logging:commons-logging:1.4.0;手动 jar 方式必须补齐后者。 - 引擎级配置(strict/silent/permissions/namespaces/cache 等
JexlBuilder构建参数):属代码级配置,逐项详解见《Apache Commons JEXL 3.7.0 配置参数详解》。
九、常见问题(FAQ)
Q1:运行报 NoClassDefFoundError: org/apache/commons/logging/LogFactory 怎么办?
classpath 缺 JEXL 3.7.0 的唯一传递依赖 commons-logging 1.4.0。Maven 工程用 mvn -q dependency:build-classpath -Dmdep.outputFile=cp.txt 生成完整 classpath 后以 $JAVA_HOME/bin/java -cp "target/classes:$(cat cp.txt)" 运行(见 4.5);二进制包方式把 commons-logging-1.4.0.jar 一并拼进 -cp(见 5.5)。
Q2:编译报 cannot find symbol: method setFunctions 怎么办?
3.7.0 已移除 JexlBuilder.setFunctions,函数注册改用 namespaces(Map)。实测报错原文:
[ERROR] /opt/jexl-demo/src/main/java/demo/FunctionNS.java:[34,17] cannot find symbol
[ERROR] symbol: method setFunctions(java.util.Map<java.lang.String,java.lang.Object>)
[ERROR] location: class org.apache.commons.jexl3.JexlBuilder
用 javap 反查 3.7.0 真实 API(实测):
javap -cp /opt/jexl3-dist/commons-jexl3-3.7.0.jar org.apache.commons.jexl3.JexlBuilder | grep -Ei "function|namespace|permission"
输出:
public java.util.Map<java.lang.String, java.lang.Object> namespaces();
public org.apache.commons.jexl3.JexlBuilder namespaces(java.util.Map<java.lang.String, java.lang.Object>);
public org.apache.commons.jexl3.introspection.JexlPermissions permissions();
public org.apache.commons.jexl3.JexlBuilder permissions(org.apache.commons.jexl3.introspection.JexlPermissions);
可见只有 namespaces / permissions,没有 setFunctions。把 .setFunctions(funcs) 改为 .namespaces(funcs) 即可。
Q3:mvn compile 失败,提示字节码版本不匹配怎么办?
Maven 或 javac 运行在了系统默认的 JDK 8 上。先 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk,再用 $JAVA_HOME/bin/java -version 2>&1 确认输出为 openjdk version "17.0.1" 2021-10-19 LTS(4.2 实测回显)后重新编译。长期方案是把 JAVA_HOME 写入 /etc/profile.d/java17.sh(见第八章)。
Q4:脚本里直接写 z = x * y 赋值报错怎么办?
3.7.0 默认禁止对未声明的全局变量赋值,实测报错:
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)
解决:用 var z = x * y; 先声明再使用(4.4 的 Main.java 即按此写法;完整演示见《Apache Commons JEXL 3.7.0 常用 API 与表达式语法详解》脚本一节)。
Q5:源码构建报 RequireMavenVersion failed with message(版本不在 [3.9,) 区间)怎么办?
3.7.0 源码工程的 enforcer 强制 Maven ≥ 3.9(6.4 实录),CentOS 8 系统自带的 3.5.4 不满足。按 6.3 下载 apache-maven-3.9.9-bin.tar.gz 解压到 /opt,用 /opt/apache-maven-3.9.9/bin/mvn package -DskipTests 构建即可,无需改动系统自带 Maven。
十、卸载与清理
JEXL 不做系统级安装,删除各方案产生的目录与包即可完全清理:
rm -rf /opt/jexl-demo /opt/jexl3-dist /opt/jexl3-demo /opt/commons-jexl3-3.7.0-src /opt/apache-maven-3.9.9 /opt/commons-jexl-3.7.0-bin.tar.gz /opt/commons-jexl-3.7.0-src.tar.gz /opt/apache-maven-3.9.9-bin.tar.gz
ls -d /opt/jexl-demo /opt/jexl3-dist /opt/jexl3-demo /opt/commons-jexl3-3.7.0-src /opt/apache-maven-3.9.9 2>/dev/null || echo "jexl directories removed"
输出:
jexl directories removed
说明:上面一次性移除 Maven 工程、二进制包解压目录、验证程序目录、源码目录与 Maven 3.9.9;ls -d 在目录全部删除后走 || 分支输出确认信息。如需同时移除 JDK 与 Maven 系统包,可执行 dnf remove -y java-17-openjdk-devel maven;本地 Maven 仓库缓存 ~/.m2 需另行清理(rm -rf ~/.m2/repository),其中缓存了 commons-jexl3-3.7.0.jar 与 commons-logging-1.4.0.jar;若配置过 /etc/profile.d/java17.sh 也一并删除。
十一、参考链接
- Apache Commons JEXL 官方站点:https://commons.apache.org/proper/commons-jexl/
- 官方发行下载目录(二进制 binaries/、源码 source/):https://downloads.apache.org/commons/jexl/
- Maven 中央仓库坐标页:https://repo1.maven.org/maven2/org/apache/commons/commons-jexl3/
- Apache Commons JEXL 3.7.0 Javadoc(官方包内
apidocs/与 javadoc jar 同内容):https://commons.apache.org/proper/commons-jexl/apidocs/ - Apache Commons JEXL 用户指南:https://commons.apache.org/proper/commons-jexl/userguide.html