CentOS 8 安装 Apache Commons Digester 指南
在 CentOS 8 从零搭建 Apache Commons Digester 使用环境,将默认 Java 1.8 切换到 JDK 17、安装 Maven 3.5.4,给出 Maven 依赖与官方发行包两种获取 jar 的方案。
CentOS 8 安装 Apache Commons Digester 指南
目标:在一台全新的 CentOS 8 服务器上搭建可编译、可运行 Apache Commons Digester 的 Java 环境,并处理 CentOS 8 默认 Java 版本过低的问题。全部命令与回显已在 CentOS Linux 8(JDK 17 + Maven 3.5.4)实测通过。
一、环境信息
本章先确认操作系统版本,再安装 JDK 17 与 Maven。CentOS 8 的一个关键差异是:系统里可能同时装了 Java 8 与 Java 17,java/javac 命令默认可能仍指向 1.8,必须显式切换。Commons Digester 3.2 的字节码目标是 Java 5(见「版本选型」章节的清单证据),JDK 8 及以上均可运行,本文统一使用 JDK 17。
先确认系统版本:
cat /etc/os-release | grep -E "^(NAME|VERSION)="
实测回显:
NAME="CentOS Linux"
VERSION="8"
查看系统里已存在的 Java 与 Maven 包:
dnf list installed | grep -Ei "java-17-openjdk|java-1.8.0-openjdk|^maven"
实测回显(输出节选,实测首尾):
java-1.8.0-openjdk.x86_64 1:1.8.0.312.b07-2.el8_5 @AppStream
java-1.8.0-openjdk-devel.x86_64 1:1.8.0.312.b07-2.el8_5 @AppStream
java-17-openjdk.x86_64 1:17.0.1.0.12-2.el8_5 @AppStream
java-17-openjdk-devel.x86_64 1:17.0.1.0.12-2.el8_5 @AppStream
maven.noarch 1:3.5.4-5.module_el8.0.0+39+6a9b6e22 @AppStream
若目标机器尚未安装,用下面的命令安装 JDK 17 与 Maven(实测同一命令在已安装时回显 Nothing to do,在未安装时执行真实安装事务):
sudo dnf install -y java-17-openjdk-devel maven
实测回显(输出节选,实测首尾):
Package java-17-openjdk-devel-1:17.0.1.0.12-2.el8_5.x86_64 is already installed.
Package maven-1:3.5.4-5.module_el8.0.0+39+6a9b6e22.noarch is already installed.
Dependencies resolved.
Nothing to do.
Complete!
首次安装时的真实安装事务如下(用 dnf reinstall 复现同一包的安装动作,可看到下载、安装、校验三个阶段):
sudo dnf -y reinstall java-17-openjdk-devel
实测回显(输出节选,实测首尾):
Total 5.1 MB/s | 5.1 MB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Preparing : 1/1
Reinstalling : java-17-openjdk-devel-1:17.0.1.0.12-2.el8_5.x86_64 1/2
Verifying : java-17-openjdk-devel-1:17.0.1.0.12-2.el8_5.x86_64 2/2
Reinstalled:
java-17-openjdk-devel-1:17.0.1.0.12-2.el8_5.x86_64
Complete!
安装完成后检查默认命令指向哪个 JDK:
readlink -f $(which java)
readlink -f $(which javac)
java -version
javac -version
实测回显:
/usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/java
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/bin/javac
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)
javac 1.8.0_312
可以看到 java 已经是 17,但 javac 仍指向 1.8.0_312,直接 javac 编译会产出 Java 8 字节码。这是 CentOS 8 用 alternatives 管理多 JDK 时的典型现象,需要把两者都切到 17:
sudo alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/javac 1
sudo alternatives --set javac /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/javac
sudo alternatives --set java /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/java
实测回显(--install 已注册过时无输出,--set 均无输出)。验证切换结果:
java -version
javac -version
alternatives --display java | grep "link currently"
alternatives --display javac | grep "link currently"
实测回显:
openjdk version "17.0.1" 2021-10-19 LTS
javac 17.0.1
link currently points to /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/java
link currently points to /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/javac
alternatives 只改 /usr/bin 下的软链,不会导出 JAVA_HOME,而 Maven 依赖 JAVA_HOME 定位编译器。写入一个开机即生效的环境变量文件:
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64' | sudo tee /etc/profile.d/java17.sh
实测回显:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
重新登录(或 source /etc/profile.d/java17.sh)后验证 Maven:
mvn -v
实测回显:
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"
输出中 Java version: 17.0.1 说明 Maven 已用上 JDK 17,环境准备完成。
💡 技术拓展:把 XML 映射成 Java 对象有多种做法,选型前要先分清各自的内存与用法代价。下表是常见选择的对比:
| 方案 | 处理方式 | 内存占用 | 代码量 | 典型场景 |
|---|---|---|---|---|
| SAX | 事件流式推送,逐节点回调 | 低 | 高(要手写回调与状态机) | 超大 XML、只读遍历 |
| DOM | 整棵树载入内存后操作 | 高 | 中 | 需随机访问、就地修改结构 |
| StAX | 拉模式流式,程序主动取事件 | 低 | 中 | 需精确控制读取流程 |
| JAXB | 注解绑定对象,需 XSD 生成类 | 中 | 低 | 标准 XML ↔ POJO 互转 |
| Digester | 规则式流式映射,边读边建对象 | 低 | 低 | 配置/规则文件转对象、无固定 Schema |
本文安装并使用的 Apache Commons Digester 属于「规则式流式映射」,不把整个 XML 载入内存,而是按注册的规则在解析到某个路径时创建对象、填属性、调方法,最适合处理结构松散、无需强校验的 XML 配置文件。
二、版本选型
Commons Digester 有两条并行发布线:org.apache.commons:commons-digester3(Digester 3,包名 org.apache.commons.digester3)与旧线 commons-digester:commons-digester(Digester 1/2,包名 org.apache.commons.digester)。本文使用 3.x 线。
先实测复核官方下载目录与 Maven 中央仓库的实际版本:
curl -fsSL https://downloads.apache.org/commons/digester/binaries/ | grep -oE "commons-digester3-[0-9.]+-bin.tar.gz" | sort -u
curl -fsSL https://repo1.maven.org/maven2/org/apache/commons/commons-digester3/maven-metadata.xml | grep -E "latest|release"
实测回显:
commons-digester3-3.2-bin.tar.gz
<latest>3.2</latest>
<release>3.2</release>
两点结论:官方下载目录当前只挂 commons-digester3-3.2 一个二进制包;Maven 中央仓库 commons-digester3 的 latest/release 同为 3.2(历史版本只有 3.0、3.1、3.2)。因此 3.x 线的最新稳定版是 3.2,并不存在坊间流传的 3.4。下表列出常用版本:
| 版本 | 发布状态 | JDK 要求 | 必需传递依赖 | 适用场景 |
|---|---|---|---|---|
| 3.2 | 3.x 最新稳定版 | Java 5 及以上(字节码目标 1.5) | cglib 2.2.2、commons-beanutils 1.8.3、commons-logging 1.1.1 | 新项目首选 |
| 3.1 | 稳定版 | Java 5 及以上 | 同 3.2 | 3.2 有兼容顾虑时的回退 |
| 3.0 | 稳定版 | Java 5 及以上 | 同 3.2 | 存量项目锁版本 |
| 2.1 | 旧线最新版(commons-digester:commons-digester) | Java 1.5 及以上 | 按旧线 pom 为准 | 老项目(Struts 1 时代)维护 |
关于「JDK 要求」的实测依据:解出 3.2 主 jar 的清单,其中 X-Compile-Source-JDK: 1.5、X-Compile-Target-JDK: 1.5;再用 javap 查看核心类,得到 major version: 49(Java 5 字节码)。因此 JDK 8/11/17/21 都能运行(本文用 JDK 17 实测)。
本文统一采用以下坐标与下载地址(均实测有效):
Maven 坐标:org.apache.commons:commons-digester3:3.2
发行包:https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz
校验文件:https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz.sha256
本地实测 sha512(本机计算):
6e27f766a6f03cada5cf505321f00c3a206721c8ca4b093364333523e625e7a1510877c75e6022301eacba9cc0f4df746f009e45f91c8847ca73d9da303097a7
两点需提前知道:Digester 3.2 没有 lib/ 目录,必需依赖(cglib、commons-beanutils、commons-logging)要自行补进类路径;官方只提供 .sha256 与 .sha1 校验文件,没有官方 .sha512。
三、方案A:Maven 中央仓库依赖
方案A通过 Maven 自动下载 jar 及其全部传递依赖,是工程化项目的推荐做法。先创建项目骨架:
mkdir -p /opt/digester-demo/src/main/java/net/quzuo/demo
mkdir -p /opt/digester-demo/src/main/resources
cd /opt/digester-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>net.quzuo.demo</groupId>
<artifactId>digester-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-digester3</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
</project>
逐项说明:maven.compiler.source/target 指定按 Java 17 语法编译;project.build.sourceEncoding 强制源码按 UTF-8 读取;dependencies 只声明 commons-digester3 一个依赖,cglib、commons-beanutils、commons-logging 作为传递依赖自动引入。
验证依赖解析结果:
mvn dependency:tree
实测回显(输出节选,实测首尾):
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ digester-demo ---
[INFO] net.quzuo.demo:digester-demo:jar:1.0.0
[INFO] \- org.apache.commons:commons-digester3:jar:3.2:compile
[INFO] +- cglib:cglib:jar:2.2.2:compile
[INFO] | \- asm:asm:jar:3.3.1:compile
[INFO] +- commons-beanutils:commons-beanutils:jar:1.8.3:compile
[INFO] \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
commons-digester3:3.2 直接依赖 cglib 2.2.2、commons-beanutils 1.8.3、commons-logging 1.1.1;cglib 2.2.2 又间接依赖 asm 3.3.1。四个依赖都是 compile 作用域,编译与运行都要在类路径里。
写入被映射的 POJO src/main/java/net/quzuo/demo/Server.java:
package net.quzuo.demo;
public class Server {
private String name;
private String host;
private int port;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getHost() { return host; }
public void setHost(String host) { this.host = host; }
public int getPort() { return port; }
public void setPort(int port) { this.port = port; }
@Override
public String toString() {
return "Server{name=" + name + ", host=" + host + ", port=" + port + "}";
}
}
写入最小验证程序 src/main/java/net/quzuo/demo/DigesterDemo.java:
package net.quzuo.demo;
import org.apache.commons.digester3.Digester;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class DigesterDemo {
public static void main(String[] args) throws Exception {
File xml = new File(args.length > 0 ? args[0] : "src/main/resources/servers.xml");
Digester d = new Digester();
d.setValidating(false);
d.addObjectCreate("servers", ArrayList.class);
d.addObjectCreate("servers/server", Server.class);
d.addSetProperties("servers/server");
d.addSetNext("servers/server", "add");
@SuppressWarnings("unchecked")
List<Server> servers = d.parse(xml);
System.out.println("解析到 " + servers.size() + " 台服务器:");
for (Server s : servers) {
System.out.println(" " + s);
}
Package p = Digester.class.getPackage();
System.out.println("commons-digester3 版本: " + p.getImplementationVersion());
}
}
程序逻辑:addObjectCreate("servers", ArrayList.class) 在进入 <servers> 时创建 ArrayList;进入 <servers/server> 时创建 Server;addSetProperties("servers/server") 把元素属性(name/host/port)按同名 setter 灌入;addSetNext("servers/server", "add") 把刚建好的 Server 通过 add 方法挂到父对象(那个 ArrayList)上;最后从 jar 清单打印库版本。
写入输入 XML src/main/resources/servers.xml:
<?xml version="1.0" encoding="UTF-8"?>
<servers>
<server name="web01" host="10.0.0.11" port="8080"/>
<server name="web02" host="10.0.0.12" port="8080"/>
<server name="db01" host="10.0.0.21" port="3306"/>
</servers>
编译并把依赖类路径导出到文件,再运行:
mvn -q compile dependency:build-classpath -Dmdep.outputFile=cp.txt
java -Dfile.encoding=UTF-8 -cp "target/classes:$(cat cp.txt)" net.quzuo.demo.DigesterDemo
实测回显:
解析到 3 台服务器:
Server{name=web01, host=10.0.0.11, port=8080}
Server{name=web02, host=10.0.0.12, port=8080}
Server{name=db01, host=10.0.0.21, port=3306}
commons-digester3 版本: 3.2
三行输出分别确认了「XML → 对象列表链路」「字段赋值正确」「jar 版本为 3.2」,方案A安装完成。程序首次运行会打印 log4j:WARN No appenders could be found for logger (org.apache.commons.digester3.Digester.sax),这是 commons-logging 1.1.1 找不到日志实现时的提示,不影响功能。
四、方案B:官方发行包手动安装
方案B适合无法使用 Maven 的机器:从官方站点下载发行包,手动拼类路径编译运行。创建安装目录并下载发行包与两个官方校验文件:
sudo mkdir -p /opt/commons
cd /opt/commons
sudo curl -fsSLO https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz
sudo curl -fsSLO https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz.sha256
sudo curl -fsSLO https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz.sha1
ls -l
实测回显:
total 4500
-rw-r--r-- 1 root root 2208821 Oct 13 16:47 commons-digester3-3.2-bin.tar.gz
-rw-r--r-- 1 root root 95 Oct 13 16:47 commons-digester3-3.2-bin.tar.gz.sha1
-rw-r--r-- 1 root root 119 Oct 13 16:47 commons-digester3-3.2-bin.tar.gz.sha256
先看校验文件的内容格式:
cat commons-digester3-3.2-bin.tar.gz.sha256
实测回显:
c2a6aa997f3d445ee4ef98c13122095e6ad6f55631c442a9cd79d4d792cc6183 *./digester/binaries/commons-digester3-3.2-bin.tar.gz
注意:官方校验文件是 BSD 格式(哈希 *路径),且路径与实际下载的文件名不同,直接 sha256sum -c 会因找不到文件而失败。把哈希拼成 哈希 文件名 再交给 sha256sum -c:
printf '%s %s\n' "$(cut -d' ' -f1 commons-digester3-3.2-bin.tar.gz.sha256)" commons-digester3-3.2-bin.tar.gz | sha256sum -c -
实测回显:
commons-digester3-3.2-bin.tar.gz: OK
同一份文件再算一次 SHA-512 供交叉比对(官方未提供 .sha512):
sha512sum commons-digester3-3.2-bin.tar.gz
实测回显:
6e27f766a6f03cada5cf505321f00c3a206721c8ca4b093364333523e625e7a1510877c75e6022301eacba9cc0f4df746f009e45f91c8847ca73d9da303097a7 commons-digester3-3.2-bin.tar.gz
校验通过后解压并查看包内容:
sudo tar xzf commons-digester3-3.2-bin.tar.gz
ls -l commons-digester3-3.2/
实测回显:
total 2384
-rw-r--r-- 1 501 wheel 13307 Dec 10 2011 LICENSE.txt
-rw-r--r-- 1 501 wheel 407 Dec 10 2011 NOTICE.txt
-rw-r--r-- 1 501 wheel 2576 Dec 10 2011 RELEASE-NOTES.txt
drwxr-xr-x 4 501 wheel 4096 Dec 10 2011 apidocs
-rw-r--r-- 1 501 wheel 852037 Dec 10 2011 commons-digester3-3.2-javadoc.jar
-rw-r--r-- 1 501 wheel 282032 Dec 10 2011 commons-digester3-3.2-sources.jar
-rw-r--r-- 1 501 wheel 734212 Dec 10 2011 commons-digester3-3.2-with-deps.jar
-rw-r--r-- 1 501 wheel 241614 Dec 10 2011 commons-digester3-3.2.jar
关键点:发行包里有两种主 jar,commons-digester3-3.2.jar 是纯库 jar,commons-digester3-3.2-with-deps.jar 是把传递依赖打进同一个 jar 的「胖包」,适合单文件交付;没有 lib/ 目录,用纯库 jar 时依赖得自己补。先演示一个必踩的坑——纯库 jar 无主类,java -jar 直接失败:
java -jar commons-digester3-3.2/commons-digester3-3.2.jar
实测回显:
no main manifest attribute, in commons-digester3-3.2/commons-digester3-3.2.jar
因为它是个供别人依赖的库,清单里没有 Main-Class。正确做法是用 -cp 列出主类。逐个下载四个传递依赖 jar 到 lib/(版本以第三章 dependency:tree 实测结果为准):
cd /opt/commons/commons-digester3-3.2
sudo mkdir -p lib
cd lib
sudo curl -fsSLO https://repo1.maven.org/maven2/cglib/cglib/2.2.2/cglib-2.2.2.jar
sudo curl -fsSLO https://repo1.maven.org/maven2/asm/asm/3.3.1/asm-3.3.1.jar
sudo curl -fsSLO https://repo1.maven.org/maven2/commons-beanutils/commons-beanutils/1.8.3/commons-beanutils-1.8.3.jar
sudo curl -fsSLO https://repo1.maven.org/maven2/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar
ls -l
实测回显:
total 616
-rw-r--r-- 1 root root 43581 asm-3.3.1.jar
-rw-r--r-- 1 root root 287192 cglib-2.2.2.jar
-rw-r--r-- 1 root root 232019 commons-beanutils-1.8.3.jar
-rw-r--r-- 1 root root 60686 commons-logging-1.1.1.jar
写入与方案A相同的两个源码文件(去掉首行 package net.quzuo.demo; 放到 /opt/commons/ 下即可),这里放 /opt/commons/Server.java 与 /opt/commons/DigesterDemo.java,同时把 servers.xml 也放到 /opt/commons/。编译并运行(用 lib/* 让 JVM 自行展开所有依赖 jar):
cd /opt/commons
CP="commons-digester3-3.2/commons-digester3-3.2.jar:commons-digester3-3.2/lib/*"
javac -encoding UTF-8 -cp "$CP" -d out Server.java DigesterDemo.java
java -Dfile.encoding=UTF-8 -cp "$CP:out" DigesterDemo servers.xml
实测回显:
解析到 3 台服务器:
Server{name=web01, host=10.0.0.11, port=8080}
Server{name=web02, host=10.0.0.12, port=8080}
Server{name=db01, host=10.0.0.21, port=3306}
commons-digester3 版本: 3.2
若不想逐个补依赖,也可以直接用胖包 commons-digester3-3.2-with-deps.jar,类路径只需它加 out:
cd /opt/commons
java -Dfile.encoding=UTF-8 -cp "commons-digester3-3.2/commons-digester3-3.2-with-deps.jar:out" DigesterDemo servers.xml
实测回显:
解析到 3 台服务器:
Server{name=web01, host=10.0.0.11, port=8080}
Server{name=web02, host=10.0.0.12, port=8080}
Server{name=db01, host=10.0.0.21, port=3306}
commons-digester3 版本: 3.2
注意 Linux 类路径分隔符是冒号 :(Windows 是分号),lib/* 的星号由 JVM 自己展开。方案B安装完成。
五、方案对比与选型建议
| 对比项 | 方案A:Maven 依赖 | 方案B:发行包手动安装 |
|---|---|---|
| 依赖管理 | 自动引入 3 个传递依赖与 asm | 手动逐个下载,漏一个就运行报错 |
| 升级成本 | 改一行版本号重新构建 | 重新下载、校验、解压、改脚本 |
| 离线部署 | 需内网私服或预下载 | 天然离线友好 |
| 可复现性 | pom 锁版本,强 | 依赖脚本与人为记录 |
| 单文件交付 | 需打包含依赖的 uber-jar | 直接分发 with-deps.jar |
| 适用场景 | 一切有构建工具的工程 | 无 Maven 的跳板机、快速验证、交付现场 |
选型建议:开发/CI 环境一律方案A;目标机器没有 Maven 或需要临时排查时用方案B;方案B的四个依赖 jar 也建议从中央仓库按 dependency:tree 实测的版本号下载,避免混用其他版本(cglib 若不带上 asm,使用内省调用时会抛 NoClassDefFoundError: org/objectweb/asm/Type)。
六、多版本管理
同一台机器上共存多个 Commons Digester 版本,推荐用「版本目录 + current 符号链接」的方式管理。先准备 3.2 与 3.1 两个版本目录(3.1 的主 jar 从中央仓库按其版本下载,依赖 jar 两版共用):
cd /opt/commons
sudo mkdir -p versions/commons-digester3-3.1/lib versions/commons-digester3-3.2/lib
sudo cp commons-digester3-3.2/commons-digester3-3.2.jar versions/commons-digester3-3.2/commons-digester3-3.2.jar
sudo cp commons-digester3-3.2/lib/*.jar versions/commons-digester3-3.2/lib/
sudo curl -fsSL -o versions/commons-digester3-3.1/commons-digester3-3.1.jar https://repo1.maven.org/maven2/org/apache/commons/commons-digester3/3.1/commons-digester3-3.1.jar
sudo cp commons-digester3-3.2/lib/*.jar versions/commons-digester3-3.1/lib/
sudo ln -sfn versions/commons-digester3-3.2 current
ls -l current
实测回显:
lrwxrwxrwx 1 root root 30 Oct 13 16:54 current -> versions/commons-digester3-3.2
写一个只打印库版本的探针 VersionProbe.java,编译一次即可反复用:
import org.apache.commons.digester3.Digester;
public class VersionProbe {
public static void main(String[] args) {
System.out.println("commons-digester3 版本: "
+ Digester.class.getPackage().getImplementationVersion());
}
}
编译(类路径含当前版本的 digester jar 与其依赖,探针代码两版通用):
cd /opt/commons
mkdir -p outv
javac -encoding UTF-8 -cp "current/commons-digester3-3.2.jar:current/lib/*" -d outv VersionProbe.java
该组命令无输出。用 current 链接运行,确认当前指向 3.2:
java -Dfile.encoding=UTF-8 -cp "current/commons-digester3-3.2.jar:current/lib/*:outv" VersionProbe
实测回显:
commons-digester3 版本: 3.2
切换链接到 3.1 后再运行(类路径里的版本 jar 同步换成 3.1):
sudo ln -sfn versions/commons-digester3-3.1 current
ls -l current
java -Dfile.encoding=UTF-8 -cp "current/commons-digester3-3.1.jar:current/lib/*:outv" VersionProbe
实测回显:
lrwxrwxrwx 1 root root 30 Oct 13 16:54 current -> versions/commons-digester3-3.1
commons-digester3 版本: 3.1
程序打印的版本号随符号链接同步变化,证明切换生效。切回最新版:
sudo ln -sfn versions/commons-digester3-3.2 current
该命令无输出。关键约束:版本 jar 路径要写成 current/commons-digester3-<版本>.jar 或让脚本按链接解析,任何一处写死成版本号目录,切换都会失效。
七、卸载
卸载分三部分:手动安装目录、Maven 本地仓库缓存、以及不再需要时的 JDK/Maven 本身。清理手动安装目录与验证产物:
sudo rm -rf /opt/commons
sudo rm -rf /opt/digester-demo
该组命令无输出。Maven 本地仓库中 digester 及其传递依赖缓存一并清理:
du -sh ~/.m2/repository/org/apache/commons/commons-digester3 ~/.m2/repository/cglib ~/.m2/repository/asm ~/.m2/repository/commons-beanutils ~/.m2/repository/commons-logging
rm -rf ~/.m2/repository/org/apache/commons/commons-digester3 ~/.m2/repository/cglib ~/.m2/repository/asm ~/.m2/repository/commons-beanutils ~/.m2/repository/commons-logging
实测回显(第一条命令,实测值):
276K /root/.m2/repository/org/apache/commons/commons-digester3
308K /root/.m2/repository/cglib
68K /root/.m2/repository/asm
484K /root/.m2/repository/commons-beanutils
196K /root/.m2/repository/commons-logging
若 JDK 17 与 Maven 也不再有他用,可一并卸载(CentOS 8 用 dnf):
sudo dnf remove -y java-17-openjdk-devel maven
实测回显(输出节选,实测首尾):
Running transaction
Preparing : 1/1
Erasing : maven-1:3.5.4-5.module_el8.0.0+39+6a9b6e22.noarc 1/135
Erasing : maven-lib-1:3.5.4-5.module_el8.0.0+39+6a9b6e22.n 2/135
Erasing : maven-wagon-http-3.1.0-1.module_el8.0.0+39+6a9b6 3/135
Erasing : java-1.8.0-openjdk-devel-1:1.8.0.312.b07-2.el8_5 14/135
Complete!
随后校验:
java -version
mvn -v
实测回显:
bash: java: command not found
bash: mvn: command not found
java/mvn 命令消失即卸载完成。两点实测注意:一是 CentOS 8 的 maven 包把 java-1.8.0-openjdk-devel 作为依赖,卸载 Maven 会连带移除它(输出中第 14 项即为该包);二是卸载过程可能出现 warning: %postun(...) scriptlet failed 与 Failed to set locale 提示,属该模块包的已知现象,不影响卸载结果。若之前用 alternatives 切过 javac,卸载后该 alternative 会失效,需要时可用 alternatives --remove javac /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/javac 清理残留项。
八、常见问题
Q1:CentOS 8 上装完 JDK 17,为什么 java 用 17 而 javac 还是 1.8?
CentOS 8 用 alternatives 机制管理多 JDK,java 与 javac 是两个独立的 alternative 组,切换 java 不会联动 javac。实测 readlink -f $(which javac) 仍指向 java-1.8.0-openjdk-...,javac -version 输出 1.8.0_312。解决:分别对两个组执行 alternatives --install 注册 JDK 17 的 javac、再 alternatives --set javac /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/javac(见第一章命令),切换后 javac -version 输出 17.0.1。
Q2:Maven 编译时找不到可用 JDK 或仍用旧版本怎么办?
alternatives 只改 /usr/bin 软链,不导出 JAVA_HOME,而 Maven 依赖 JAVA_HOME。实测未设置时 echo $JAVA_HOME 为空。解决:写入 /etc/profile.d/java17.sh 导出 JAVA_HOME,重新登录后用 mvn -v 检查,其 Java version: 行应为 17.0.1。
Q3:java -jar commons-digester3-3.2.jar 报 no main manifest attribute 怎么办?
这是设计如此:纯库 jar 只供其他项目依赖,清单里没有 Main-Class。要么改用 java -cp "主jar:lib/*" 你的主类,要么直接用胖包 commons-digester3-3.2-with-deps.jar 并带上你的类目录。
Q4:运行时报 NoClassDefFoundError: org/objectweb/asm/Type 或 beanutils 包下的类找不到,怎么处理?
说明传递依赖没进类路径。3.2 的必需依赖是 cglib 2.2.2(其又依赖 asm 3.3.1)、commons-beanutils 1.8.3、commons-logging 1.1.1,Maven 项目会自动带入;手动部署时必须把四个 jar 全部放进 lib/,或直接用 with-deps.jar。
Q5:为什么 3.x 线最新版是 3.2 而不是 3.4?
实测 Maven 中央仓库 commons-digester3 的 maven-metadata.xml 中 <latest>/<release> 均为 3.2,可用版本只有 3.0、3.1、3.2;官方下载目录也只挂 3.2。3.2 发布于 2011 年后长期未再发新版,所谓「3.4」并不存在,选型请以实测目录页为准。
九、参考链接
- Apache Commons Digester 官方主页:https://commons.apache.org/proper/commons-digester/
- 3.2 发行包下载:https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz
- 发行包 sha256 校验文件:https://downloads.apache.org/commons/digester/binaries/commons-digester3-3.2-bin.tar.gz.sha256
- Maven 中央仓库 commons-digester3 目录(含 pom 与各分类 jar):https://repo1.maven.org/maven2/org/apache/commons/commons-digester3/3.2/
- Apache 归档下载站(历史版本):https://archive.apache.org/dist/commons/digester/binaries/
- 官方 javadoc(3.2 在线 API 文档):https://commons.apache.org/proper/commons-digester/apidocs/index.html
- CentOS 8 JDK 17 包说明:https://vault.centos.org/8.5.2111/AppStream/x86_64/os/Packages/
- Maven 安装文档:https://maven.apache.org/install.html