Ubuntu 22.04 安装 Apache Commons Digester 指南
在 Ubuntu 22.04 从零搭建 Apache Commons Digester 使用环境,安装 JDK 17 与 Maven,给出 Maven 依赖与官方发行包两种获取 jar 的方案,含校验与最小验证程序。
Ubuntu 22.04 安装 Apache Commons Digester 指南
目标:在一台全新的 Ubuntu 22.04 服务器上搭建可编译、可运行 Apache Commons Digester 的 Java 环境,并提供 Maven 依赖与官方发行包两种获取 jar 的方案。全部命令与回显已在 Ubuntu 22.04(JDK 17 + Maven 3.6.3)实测通过。
一、环境信息
本章先确认操作系统版本,再安装 JDK 17 与 Maven,为后续获取 Commons Digester 做准备。Commons Digester 3.2 的字节码编译目标很低(后面「版本选型」章节会给出清单证据),JDK 8 及以上运行均可,本文统一使用 JDK 17 作为开发与运行环境。
先确认系统版本:
cat /etc/os-release | grep -E "^(NAME|VERSION)="
实测回显:
NAME="Ubuntu"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
安装 JDK 17 与 Maven(约 1~2 分钟,取决于网络):
sudo apt update
sudo apt install -y openjdk-17-jdk maven
实测回显(输出节选,实测首尾):
Reading package lists... Done
Building dependency tree... Done
The following additional packages will be installed:
openjdk-17-jdk-headless openjdk-17-jre openjdk-17-jre-headless
Suggested packages:
openjdk-17-demo openjdk-17-source visualvm maven-docs
Setting up openjdk-17-jdk:amd64 (17.0.20.1+1-1~22.04) ...
Setting up maven (3.6.3-5) ...
验证安装结果:
java -version
javac -version
mvn -v
实测回显:
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)
javac 17.0.20.1
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
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.20.1 说明 Maven 已经用上了刚安装的 JDK 17。若这一行显示的是其他版本,请在 ~/.bashrc 中追加 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 后重新登录。
💡 技术拓展:把 XML 映射成 Java 对象,业界有多套方案,选型前要先分清各自的内存与用法代价。下表是常见选择的对比:
| 方案 | 处理方式 | 内存占用 | 代码量 | 典型场景 |
|---|---|---|---|---|
| SAX | 事件流式推送,逐节点回调 | 低 | 高(要手写回调与状态机) | 超大 XML、只读遍历 |
| DOM | 整棵树载入内存后操作 | 高 | 中 | 需随机访问、就地修改结构 |
| StAX | 拉模式流式,程序主动取事件 | 低 | 中 | 需精确控制读取流程 |
| JAXB | 注解绑定对象,需 XSD 生成类 | 中 | 低 | 标准 XML ↔ POJO 互转 |
| Digester | 规则式流式映射,边读边建对象 | 低 | 低 | 配置/规则文件转对象、无固定 Schema |
本文安装并使用的 Apache Commons Digester 属于「规则式流式映射」:不把整个 XML 载入内存,而是按注册的规则在解析到某个路径时创建对象、填属性、调方法。它最初从 Struts 项目中演化而来,最适合处理「结构松散、无需强校验」的 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 字节码)。三者一致表明 3.2 的字节码目标是 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,本机的 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 找不到日志实现时的提示,不影响功能;若在意可加入 log4j 配置或改依赖 slf4j。
四、方案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:29 commons-digester3-3.2-bin.tar.gz
-rw-r--r-- 1 root root 54 Oct 13 16:29 commons-digester3-3.2-bin.tar.gz.sha1
-rw-r--r-- 1 root root 99 Oct 13 16:29 commons-digester3-3.2-bin.tar.gz.sha256
先看两个校验文件的内容格式:
cat commons-digester3-3.2-bin.tar.gz.sha256
cat commons-digester3-3.2-bin.tar.gz.sha1
实测回显:
c2a6aa997f3d445ee4ef98c13122095e6ad6f55631c442a9cd79d4d792cc6183 *./digester/binaries/commons-digester3-3.2-bin.tar.gz
4fe53e0ce99766cdfd45e4776dca1dfb50271f5d *./digester/binaries/commons-digester3-3.2-bin.tar.gz
注意:官方校验文件是 BSD 格式(哈希 *路径),且路径与实际下载的文件名不同,直接 sha256sum -c 会因找不到文件而失败。实测确认 SHA-256 与 SHA-1 哈希后,把哈希拼成 哈希 文件名 再交给 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 2184
-rw-r--r-- 1 501 root 241614 Dec 10 2011 commons-digester3-3.2.jar
-rw-r--r-- 1 501 root 852037 Dec 10 2011 commons-digester3-3.2-javadoc.jar
-rw-r--r-- 1 501 root 282032 Dec 10 2011 commons-digester3-3.2-sources.jar
-rw-r--r-- 1 501 root 734212 Dec 10 2011 commons-digester3-3.2-with-deps.jar
drwxr-xr-x 3 501 root 4096 Dec 10 2011 apidocs
关键点:发行包里有两种主 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 468
-rw-r--r-- 1 root root 43581 cglib-2.2.2.jar
-rw-r--r-- 1 root root 287192 asm-3.3.1.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 自己展开,不要加引号阻止 shell 与 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 符号链接」的方式管理:所有版本平铺在 /opt/commons/versions/ 下,current 指向当前生效版本,切换时只改链接。先准备 3.2 与 3.1 两个版本目录(3.1 的主 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
实测回显(输出节选,实测首尾):
lrwxrwxrwx 1 root root 30 Oct 13 16:48 current -> versions/commons-digester3-3.2
drwxr-xr-x 2 root root 4096 Oct 13 16:48 commons-digester3-3.1
drwxr-xr-x 2 root root 4096 Oct 13 16:48 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(current 指向哪个目录就加载哪个版本):
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:48 current -> versions/commons-digester3-3.1
commons-digester3 版本: 3.1
程序打印的版本号随符号链接同步变化,证明切换生效。切回最新版:
sudo ln -sfn versions/commons-digester3-3.2 current
该命令无输出。这套机制的关键约束是:版本 jar 路径必须写成 current/commons-digester3-<版本>.jar 或让脚本按链接解析,任何一处写死成具体的版本目录(如 commons-digester3-3.2),切换都会失效。
七、卸载
卸载分三部分:手动安装目录、Maven 本地仓库缓存、以及不再需要时的 JDK/Maven 本身。清理手动安装目录与验证产物:
sudo rm -rf /opt/commons
sudo rm -rf /opt/digester-demo
该组命令无输出。Maven 本地仓库中 digester 及其传递依赖缓存总计约 1.3MB,一并清理:
du -sh ~/.m2/repository/org/apache/commons/commons-digester3 ~/.m2/repository/cglib/cglib ~/.m2/repository/asm/asm ~/.m2/repository/commons-beanutils/commons-beanutils ~/.m2/repository/commons-logging/commons-logging
实测回显:
276K /root/.m2/repository/org/apache/commons/commons-digester3
308K /root/.m2/repository/cglib/cglib
68K /root/.m2/repository/asm/asm
484K /root/.m2/repository/commons-beanutils/commons-beanutils
196K /root/.m2/repository/commons-logging/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
该命令无输出。若 JDK 17 与 Maven 也不再有他用,可一并卸载。先移除 Maven 与 JDK 主包:
sudo apt remove -y openjdk-17-jdk maven
实测回显(输出节选,实测首尾):
The following packages will be REMOVED:
maven openjdk-17-jdk
0 upgraded, 0 newly installed, 2 to remove and 1 not upgraded.
After this operation, 1723 kB disk space will be freed.
Removing maven (3.6.3-5) ...
Removing openjdk-17-jdk:amd64 (17.0.20.1+1-1~22.04) ...
注意:openjdk-17-jdk 只是一个元包,真正提供 java/javac 的是 openjdk-17-jdk-headless 与 openjdk-17-jre 等被自动安装的依赖包,因此此刻直接检查会发现 java 仍可用、只有 mvn 消失:
java -version
mvn -v
实测回显:
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)
bash: line 1: mvn: command not found
再执行自动清理,把不再被依赖的 JDK 相关包一并移除:
sudo apt autoremove -y
java -version
javac -version
mvn -v
实测回显(输出节选,实测首尾):
Processing triggers for ca-certificates (20260601~22.04.1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...
bash: line 1: java: command not found
bash: line 1: javac: command not found
bash: line 1: mvn: command not found
java/javac/mvn 命令全部消失即卸载完成。注意:~/.m2 中其他项目的依赖缓存不受本次卸载影响,若要彻底清空可再执行 rm -rf ~/.m2。
八、常见问题
Q1:为什么 3.x 线最新版是 3.2 而不是 3.4?
实测 repo1.maven.org 上 org/apache/commons/commons-digester3/maven-metadata.xml 的 <latest> 与 <release> 都是 3.2,可用版本只有 3.0、3.1、3.2;官方下载目录 downloads.apache.org/commons/digester/binaries/ 当前也仅挂 3.2。Digester 3 系列在 2011 年发布 3.2 后长期未再发新版,所谓「3.4」并不存在,选型时以实测目录页为准,不要臆造版本号。
Q2: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 并在类路径里带上你的类目录。
Q3:运行时报 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。
Q4:程序里打印的中文在终端显示成问号或乱码怎么办?
这是 locale 问题而不是库的问题。实测本机 mvn -v 显示 platform encoding: ANSI_X3.4-1968,Java 程序的 System.out 会退回 ASCII。解决:export LANG=C.UTF-8 写入 ~/.bashrc,或运行时追加 -Dfile.encoding=UTF-8。
Q5:怎么确认程序加载的 Digester 就是想要的版本?
用本文 DigesterDemo 里的 Digester.class.getPackage().getImplementationVersion(),它读取 jar 清单的 Implementation-Version,实测 3.2 会打印 commons-digester3 版本: 3.2。Maven 场景还可以用 mvn dependency:tree 核对解析结果。
九、参考链接
- 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
- OpenJDK 17 Ubuntu 安装文档:https://packages.ubuntu.com/jammy/openjdk-17-jdk
- Maven 安装文档:https://maven.apache.org/install.html