Ubuntu 22.04 安装 Apache Xerces 指南
面向 Ubuntu 22.04 的 Apache Xerces 部署指南:安装 OpenJDK 17 与 Maven,引入 xercesImpl 2.12.2,实测 DOM、SAX、XSD 校验与 JAXP 切换,含堆参数配置与卸载方法。
Ubuntu 22.04 安装 Apache Xerces 指南
一、环境信息
1.1 服务器与软件版本
本文全部步骤均在 Ubuntu 22.04 服务器上实测完成,版本信息如下:
| 项目 | 实测版本 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(Jammy,x86_64) |
| JDK | OpenJDK 17.0.20.1(openjdk-17-jdk 17.0.20.1+1-1~22.04) |
| 构建工具 | Apache Maven 3.6.3(3.6.3-5) |
| Apache Xerces | Xerces-J 2.12.2(xerces:xercesImpl,Maven Central 实测最新版) |
| 传递依赖 | xml-apis 1.4.01(随 xercesImpl 自动引入) |
1.2 账号说明
本文所有命令均以 root 账号执行(演示账号 root,密码 q1w2e3r4)。普通用户执行 apt-get install 时需加 sudo。
1.3 软件源说明
使用系统默认的 Ubuntu 官方源即可,apt-get update 实测正常。无特殊网络要求,仅需保证能访问 Maven Central(repo.maven.apache.org)。
二、前置条件
2.1 资源要求
- CPU:2 核即可(实测构建与解析均在秒级完成);
- 内存:不低于 2 GB(实测解析 38.2 MB XML 时 DOM 峰值堆占用约 456 MB,JVM 堆上限按 512 MB 配置);
- 磁盘:不低于 5 GB(openjdk-17-jdk 与 Maven 安装后约 1 GB,本地 Maven 仓库约 300 MB,余量留给工程);
- 网络:能访问 archive.ubuntu.com 与 Maven Central。
2.2 刷新软件源索引
apt-get update
实测尾部回显:
All packages are up to date.
(首次执行会显示各源 Hit/Get 行,只要最后无 Err 即可。)
2.3 检查既有 Java 环境
java -version
实测全新服务器回显:
bash: java: command not found
若已安装 OpenJDK 11(/usr/lib/jvm 下会同时出现 java-1.11.0 与 java-1.17.0 目录),apt-get install openjdk-17-jdk 会通过 update-alternatives 自动把默认 java 指向 17,无需手动切换;安装后务必按 4.1 节复核。
三、版本选型
3.1 Xerces-J 与 JDK 内置 Xerces 的关系与差异
Java 生态中的 "Xerces" 有两套并存的实现:
| 对比项 | JDK 内置实现 | Xerces-J 独立版 |
|---|---|---|
| 包名前缀 | com.sun.org.apache.xerces.internal.* | org.apache.xerces.* |
| 发布渠道 | 随 JDK 发布,不可单独升级 | Maven Central 独立发布(实测最新 2.12.2,发布于 2022-01-27) |
| JAXP 工厂类 | com.sun.org.apache.xerces.internal.jaxp.* | org.apache.xerces.jaxp.* |
| 缺陷修复 | 取决于 JDK 版本节奏 | 社区独立修复,但 2.12.2 后已无新版本 |
| 附加能力 | 无原生解析器类 | 提供 org.apache.xerces.parsers.DOMParser/SAXParser 原生类与扩展特性集 |
两者都实现 JAXP 标准接口(javax.xml.parsers.*、javax.xml.validation.*),业务代码面向接口编写即可无缝切换。是否引入独立版,取决于是否需要 Xerces 扩展特性、扩展属性或原生解析器类。
3.2 版本获取渠道
- Maven 坐标:
xerces:xercesImpl:2.12.2(Maven Central 实测 latestVersion 为 2.12.2); - 官方二进制包:
Xerces-J-bin.2.12.2.tar.gz,实测从 archive.apache.org 下载,大小 5,648,672 字节,SHA-256 为1ad48949b2c7f0df91668f058d6ec773871adb5527b0b5c73dc2160ab5d162e2。
四、部署步骤
4.1 安装 OpenJDK 17
apt-get install -y openjdk-17-jdk
实测尾部回显:
Processing triggers for libgdk-pixbuf-2.0-0:amd64 (2.42.8+dfsg-1ubuntu0.5) ...
验证:
# java -version
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 -version
javac 17.0.20.1
4.2 安装 Maven
apt-get install -y maven
验证:
# mvn -version
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"
4.3 创建 Maven 工程
mkdir -p /root/xerces-demo/src/main/java/com/example/xerces
mkdir -p /root/xerces-demo/src/main/resources
cd /root/xerces-demo
目录结构:
/root/xerces-demo
├── pom.xml
└── src/main
├── java/com/example/xerces
└── resources
编写 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>com.example</groupId>
<artifactId>xerces-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>
</project>
4.4 引入 xercesImpl 依赖并构建
cd /root/xerces-demo
mvn -q package
构建成功后确认本地仓库中的依赖文件:
# ls /root/.m2/repository/xerces/xercesImpl/2.12.2/
_remote.repositories
xercesImpl-2.12.2.jar
xercesImpl-2.12.2.jar.sha1
xercesImpl-2.12.2.pom
xercesImpl-2.12.2.pom.sha1
导出完整运行时 classpath(可见 xercesImpl 自动带入 xml-apis 1.4.01):
mvn -q dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt
cat /tmp/cp.txt
实测回显:
/root/xerces-demo/target/classes:/root/.m2/repository/xerces/xercesImpl/2.12.2/xercesImpl-2.12.2.jar:/root/.m2/repository/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar
4.5 准备样例 XML 与 XSD
src/main/resources/books.xml(合法样例):
<?xml version="1.0" encoding="UTF-8"?>
<books xmlns="http://www.example.com/books">
<book id="101">
<title>Java核心技术</title>
<author>周志明</author>
<price>129.00</price>
</book>
<book id="102">
<title>Effective Java</title>
<author>Joshua Bloch</author>
<price>108.50</price>
</book>
</books>
src/main/resources/books.xsd(Schema 定义):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.com/books"
targetNamespace="http://www.example.com/books"
elementFormDefault="qualified">
<xs:element name="books" type="tns:BooksType"/>
<xs:complexType name="BooksType">
<xs:sequence>
<xs:element name="book" type="tns:BookType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="BookType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="id" type="xs:int" use="required"/>
</xs:complexType>
</xs:schema>
src/main/resources/books-invalid.xml(违反 Schema:缺 id 属性、price 不是数字):
<?xml version="1.0" encoding="UTF-8"?>
<books xmlns="http://www.example.com/books">
<book id="101">
<title>Java核心技术</title>
<author>周志明</author>
<price>129.00</price>
</book>
<book>
<title>Effective Java</title>
<author>Joshua Bloch</author>
<price>not-a-number</price>
</book>
</books>
src/main/resources/books-badwf.xml(格式不合法:根元素未闭合):
<?xml version="1.0" encoding="UTF-8"?>
<!-- 故意制造标签未闭合的格式错误,用于演示解析器致命错误 -->
<books xmlns="http://www.example.com/books">
<book id="101">
<title>Java核心技术</title>
<author>周志明</author>
<price>129.00</price>
</book>
4.6 DOM 解析验证
编写 src/main/java/com/example/xerces/DomDemo.java:
package com.example.xerces;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class DomDemo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
System.out.println("DocumentBuilderFactory 实现: " + factory.getClass().getName());
factory.setNamespaceAware(true); // 默认 false,关闭时按命名空间查找将得到 0 个节点
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("src/main/resources/books.xml"));
Element root = doc.getDocumentElement();
System.out.println("根元素: " + root.getTagName());
NodeList books = root.getElementsByTagNameNS("*", "book");
System.out.println("book 节点数: " + books.getLength());
for (int i = 0; i < books.getLength(); i++) {
Element book = (Element) books.item(i);
String id = book.getAttribute("id");
String title = book.getElementsByTagNameNS("*", "title").item(0).getTextContent();
String author = book.getElementsByTagNameNS("*", "author").item(0).getTextContent();
String price = book.getElementsByTagNameNS("*", "price").item(0).getTextContent();
System.out.println("book[" + i + "] id=" + id + " | " + title + " | " + author + " | " + price);
}
}
}
编译并运行(注意携带 UTF-8 locale,否则中文输出会变成问号):
export LC_ALL=C.UTF-8
java -cp target/classes:$(cat /tmp/cp.txt) com.example.xerces.DomDemo
实测回显:
DocumentBuilderFactory 实现: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
根元素: books
book 节点数: 2
book[0] id=101 | Java核心技术 | 周志明 | 129.00
book[1] id=102 | Effective Java | Joshua Bloch | 108.50
4.7 SAX 事件流解析验证
编写 src/main/java/com/example/xerces/SaxDemo.java:
package com.example.xerces;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.XMLReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class SaxDemo {
public static void main(String[] args) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
// 传入参数 ns 开启命名空间感知;默认 false,此时 uri 与 localName 均为空串
if (args.length > 0 && "ns".equals(args[0])) {
factory.setNamespaceAware(true);
}
System.out.println("SAXParserFactory 实现: " + factory.getClass().getName()
+ " (namespaceAware=" + factory.isNamespaceAware() + ")");
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
reader.setContentHandler(new ContentHandler() {
@Override
public void setDocumentLocator(Locator locator) {
System.out.println("[setDocumentLocator] systemId=" + locator.getSystemId());
}
@Override
public void startDocument() {
System.out.println("[startDocument]");
}
@Override
public void endDocument() {
System.out.println("[endDocument]");
}
@Override
public void startPrefixMapping(String prefix, String uri) {
}
@Override
public void endPrefixMapping(String prefix) {
}
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < atts.getLength(); i++) {
sb.append(" ").append(atts.getQName(i)).append("=").append(atts.getValue(i));
}
System.out.println("[startElement] uri=" + uri + " localName=" + localName + " qName=" + qName + sb);
}
@Override
public void endElement(String uri, String localName, String qName) {
System.out.println("[endElement] " + qName);
}
@Override
public void characters(char[] ch, int start, int length) {
String text = new String(ch, start, length).trim();
if (!text.isEmpty()) {
System.out.println("[characters] " + text);
}
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length) {
}
@Override
public void processingInstruction(String target, String data) {
}
@Override
public void skippedEntity(String name) {
}
});
reader.parse("src/main/resources/books.xml");
}
}
运行(命名空间感知模式,截取开头片段):
java -cp target/classes:$(cat /tmp/cp.txt) com.example.xerces.SaxDemo ns
实测回显:
SAXParserFactory 实现: org.apache.xerces.jaxp.SAXParserFactoryImpl (namespaceAware=true)
[setDocumentLocator] systemId=file:///root/xerces-demo/src/main/resources/books.xml
[startDocument]
[startElement] uri=http://www.example.com/books localName=books qName=books
[startElement] uri=http://www.example.com/books localName=book qName=book id=101
[startElement] uri=http://www.example.com/books localName=title qName=title
[characters] Java核心技术
[endElement] title
...
[endElement] books
[endDocument]
4.8 XSD Schema 校验验证
编写 src/main/java/com/example/xerces/ValidateDemo.java:
package com.example.xerces;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
public class ValidateDemo {
public static void main(String[] args) throws Exception {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
System.out.println("SchemaFactory 实现: " + schemaFactory.getClass().getName());
Schema schema = schemaFactory.newSchema(new File("src/main/resources/books.xsd"));
Validator validator = schema.newValidator();
String[] files = {
"src/main/resources/books.xml",
"src/main/resources/books-invalid.xml",
"src/main/resources/books-badwf.xml"
};
for (String file : files) {
System.out.println("==== 校验 " + file + " ====");
validator.reset();
final int[] errors = {0}; // error() 回调不抛异常时校验器会继续跑完,须自行计数
validator.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException e) {
System.out.println("[WARNING] 行 " + e.getLineNumber() + " 列 " + e.getColumnNumber() + ": " + e.getMessage());
}
@Override
public void error(SAXParseException e) {
errors[0]++;
System.out.println("[ERROR] 行 " + e.getLineNumber() + " 列 " + e.getColumnNumber() + ": " + e.getMessage());
}
@Override
public void fatalError(SAXParseException e) throws SAXParseException {
errors[0]++;
System.out.println("[FATAL] 行 " + e.getLineNumber() + " 列 " + e.getColumnNumber() + ": " + e.getMessage());
throw e;
}
});
try {
validator.validate(new StreamSource(new File(file)));
if (errors[0] == 0) {
System.out.println("结果: 校验通过");
} else {
System.out.println("结果: 校验失败,共报告 " + errors[0] + " 处错误");
}
} catch (SAXParseException e) {
System.out.println("结果: 校验失败(致命错误已中断解析)");
}
}
}
}
运行:
java -cp target/classes:$(cat /tmp/cp.txt) com.example.xerces.ValidateDemo
实测回显(合法文件通过、违规文件报出 cvc 错误码与行列号、格式错误文件报致命错误):
SchemaFactory 实现: org.apache.xerces.jaxp.validation.XMLSchemaFactory
==== 校验 src/main/resources/books.xml ====
结果: 校验通过
==== 校验 src/main/resources/books-invalid.xml ====
[ERROR] 行 8 列 11: cvc-complex-type.4: Attribute 'id' must appear on element 'book'.
[ERROR] 行 11 列 36: cvc-datatype-valid.1.2.1: 'not-a-number' is not a valid value for 'decimal'.
[ERROR] 行 11 列 36: cvc-type.3.1.3: The value 'not-a-number' of element 'price' is not valid.
结果: 校验失败,共报告 3 处错误
==== 校验 src/main/resources/books-badwf.xml ====
[FATAL] 行 9 列 1: XML document structures must start and end within the same entity.
结果: 校验失败(致命错误已中断解析)
4.9 JAXP 实现切换验证
编写 src/main/java/com/example/xerces/JaxpSwitchDemo.java:
package com.example.xerces;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
public class JaxpSwitchDemo {
public static void main(String[] args) throws Exception {
System.out.println("javax.xml.parsers.DocumentBuilderFactory = "
+ System.getProperty("javax.xml.parsers.DocumentBuilderFactory", "(未设置)"));
System.out.println("实际 DocumentBuilderFactory 实现: "
+ DocumentBuilderFactory.newInstance().getClass().getName());
System.out.println("javax.xml.parsers.SAXParserFactory = "
+ System.getProperty("javax.xml.parsers.SAXParserFactory", "(未设置)"));
System.out.println("实际 SAXParserFactory 实现: "
+ SAXParserFactory.newInstance().getClass().getName());
}
}
三种场景实测:
# 场景 1:classpath 不含 xercesImpl,使用 JDK 内置实现
java -cp target/classes com.example.xerces.JaxpSwitchDemo
# 场景 2:classpath 含 xercesImpl,观察自动切换
java -cp target/classes:$(cat /tmp/cp.txt) com.example.xerces.JaxpSwitchDemo
# 场景 3:显式用系统属性指定 Xerces 实现
java -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
-Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl \
-cp target/classes com.example.xerces.JaxpSwitchDemo
实测回显(依次为场景 1、2、3):
场景 1:
javax.xml.parsers.DocumentBuilderFactory = (未设置)
实际 DocumentBuilderFactory 实现: com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
javax.xml.parsers.SAXParserFactory = (未设置)
实际 SAXParserFactory 实现: com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
场景 2:
javax.xml.parsers.DocumentBuilderFactory = (未设置)
实际 DocumentBuilderFactory 实现: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
javax.xml.parsers.SAXParserFactory = (未设置)
实际 SAXParserFactory 实现: org.apache.xerces.jaxp.SAXParserFactoryImpl
场景 3:
javax.xml.parsers.DocumentBuilderFactory = org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
实际 DocumentBuilderFactory 实现: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
javax.xml.parsers.SAXParserFactory = org.apache.xerces.jaxp.SAXParserFactoryImpl
实际 SAXParserFactory 实现: org.apache.xerces.jaxp.SAXParserFactoryImpl
五、配置说明
5.1 JVM 堆参数
XML 解析对堆敏感,建议统一按 256–512 MB 配置。修改位置为 /etc/profile.d/xerces-maven.sh(新建文件,登录 shell 全局生效):
echo 'export MAVEN_OPTS="-Xms256m -Xmx512m"' > /etc/profile.d/xerces-maven.sh
注意两点:
- 不要写在
/root/.bashrc里:非交互 shell 会因 bashrc 开头的交互检测而提前 return,实测 source 后MAVEN_OPTS仍为空; - Maven 3.6.3 的
mvn -version不会打印 MAVEN_OPTS,需要用进程工具验证。
验证方式一:后台启动解析进程后用 jps 查看实际生效的 JVM 参数(实测回显):
# jps -lv
7857 com.example.xerces.BigXmlDom -Xms256m -Xmx512m
7910 jdk.jcmd/sun.tools.jps.Jps -Dapplication.home=/usr/lib/jvm/java-17-openjdk-amd64 -Xms8m -Djdk.module.main=jdk.jcmd
验证方式二:ps -ef | grep [j]ava 查看完整命令行(实测回显):
root 7857 7848 99 14:46 ? 00:00:06 java -Xms256m -Xmx512m -cp target/classes:/root/.m2/repository/xerces/xercesImpl/2.12.2/xercesImpl-2.12.2.jar:/root/.m2/repository/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar com.example.xerces.BigXmlDom /root/xerces-demo/big-books.xml 20
直接用 java 命令运行时,把堆参数写进命令行即可,也可通过 JAVA_OPTS 变量传递:
export JAVA_OPTS="-Xms256m -Xmx512m"
java $JAVA_OPTS -cp target/classes:$(cat /tmp/cp.txt) com.example.xerces.DomDemo
5.2 字符集与 locale
Ubuntu 22.04 默认 locale 可能是 POSIX,程序中的中文会输出为问号(实测输出形如 ????Java???)。确认并设置:
locale -a | grep -i utf
echo 'export LC_ALL=C.UTF-8' > /etc/profile.d/lang.sh
实测本机存在 C.utf8,直接引用 C.UTF-8 即可生效。
5.3 Maven 相关
- 本地仓库位置:
/root/.m2/repository; - 远程仓库:默认中央仓库直连可用,实测可正常下载 xercesImpl 2.12.2;
- 全局配置文件:
/usr/share/maven/conf/settings.xml,用户级为~/.m2/settings.xml。
六、升级与多版本
6.1 Maven 依赖升级
修改 pom.xml 中 xercesImpl 的 <version> 后重新执行 mvn -q package,新版本 jar 会进入本地仓库对应目录,旧版本目录保留,互不影响。
6.2 官方二进制包多版本共存
从 archive.apache.org 下载不同版本的 Xerces-J-bin.x.y.z.tar.gz,分别解压到 /opt/xerces-2_12_2、/opt/xerces-2_11_0 等独立目录,运行时用 -cp 显式指定目录内 jar:
java -cp /opt/xerces-2_12_2/xercesSamples.jar:/opt/xerces-2_12_2/xercesImpl.jar:/opt/xerces-2_12_2/xml-apis.jar:/opt/xerces-2_12_2/serializer.jar:/opt/xerces-2_12_2/samples/xs sax.Counter /opt/xerces-2_12_2/data/personal.xml
6.3 实现选择优先级
JAXP 选择实现的优先级(实测结论):系统属性 -D 最高;其次是 classpath 中 jar 包内 META-INF/services 声明(ServiceLoader);都没有时回落到 JDK 内置实现。因此"是否升级 xercesImpl"不会影响未引入该依赖的应用。
七、注意事项
- 引入 xercesImpl 后 JAXP 默认实现被静默接管。 xercesImpl-2.12.2.jar 内含
META-INF/services/javax.xml.parsers.DocumentBuilderFactory等声明文件,只要出现在 classpath,DocumentBuilderFactory.newInstance()就会返回org.apache.xerces.jaxp.DocumentBuilderFactoryImpl(实测)。混用多个 XML 库时需注意行为差异。 - 解析器默认不感知命名空间。
DocumentBuilderFactory与SAXParserFactory的namespaceAware默认均为 false,此时getElementsByTagNameNS返回 0 个节点、SAX 回调的 uri/localName 为空串(实测)。需要命名空间时必须显式setNamespaceAware(true)。 - ErrorHandler 的 error() 不抛异常时校验会"照常通过"。 实测 error 回调只打印不抛出时,
validator.validate()正常返回,结论必须结合错误计数判断。 - jcmd/jinfo 可能不可用。 实测对运行中的 JVM 执行
jcmd VM.flags、jinfo -flag均报Unable to open socket file /tmp/.java_pidXXXX: target process doesn't respond within 10500ms or HotSpot VM not loaded,此时改用jps -lv、jstat -gcutil验证 JVM 参数与 GC 状态。 - apt 版本随源更新。 openjdk-17-jdk 的候选版本随 Ubuntu 补丁更新(实测 17.0.20.1+1-1~22.04),
apt-cache policy openjdk-17-jdk可确认实际安装版本。 - locale 问题优先排查。 输出中文变问号时先用
locale命令确认当前值,再看locale -a中可用的 UTF-8 项。
八、常见问题
Q1:apt-get install 报 404 或 Hash Sum mismatch?
先执行 apt-get update 刷新索引;仍失败时检查 /etc/apt/sources.list 是否被改为失效的第三方地址,恢复官方源后重试。
Q2:程序运行时中文全部显示为问号(如 ????Java???)?
系统 locale 为 POSIX 所致。执行 export LC_ALL=C.UTF-8(建议写入 /etc/profile.d/lang.sh),重新登录 shell 后生效。
Q3:getElementsByTagNameNS("*", "book") 返回 0 个节点?
解析器默认不感知命名空间。在 DocumentBuilderFactory.newInstance() 之后调用 factory.setNamespaceAware(true) 再创建 DocumentBuilder(实测默认关闭时返回 0,开启后返回 2)。
Q4:把 -Xmx 调到 256m 后大文件解析报错?
实测 38.2 MB XML 用 DOM 全量加载,堆峰值约 456 MB。堆上限 256 MB 时实测报 An exception occurred while executing the Java class. Java heap space。建议按第五节配置 512 MB,或改用 SAX 流式解析。
Q5:mvn package 时报 source option 8 is obsolete 警告?
JDK 17 编译 target 8 的过时提示,不影响构建产物,可忽略;如需消除可把 maven.compiler.source/target 提升到与运行时一致的版本。
Q6:安装 openjdk-17-jdk 时自动装了 OpenJDK 11?
openjdk-17-jdk 依赖链可能带出 11 号 JDK 作为依赖(/usr/lib/jvm 下可见 java-1.11.0 目录),属正常现象;update-alternatives 已把默认 java 指向 17,用 java -version 复核即可。
九、卸载方式
按依赖顺序回退(先删应用数据,再删组件包):
rm -rf /root/xerces-demo
rm -rf /root/.m2
rm -f /etc/profile.d/xerces-maven.sh /etc/profile.d/lang.sh
rm -rf /opt/xerces-2_12_2 /opt/Xerces-J-bin.2.12.2.tar.gz
apt-get remove -y openjdk-17-jdk maven
如需连依赖与配置一并清理,可再执行 apt-get purge -y openjdk-17-jdk maven && apt-get autoremove -y。
卸载后验证:
java -version
mvn -version
两者均应提示 command not found。
十、参考链接
- Xerces2 Java 官方站点:https://xerces.apache.org/xerces2-j/
- 解析器特性(features)官方清单:https://xerces.apache.org/xerces2-j/features.html
- 解析器属性(properties)官方清单:https://xerces.apache.org/xerces2-j/properties.html
- Maven Central 构件页:https://central.sonatype.com/artifact/xerces/xercesImpl
- Maven Central 仓库目录:https://repo1.maven.org/maven2/xerces/xercesImpl/
- 源码仓库:https://github.com/apache/xerces-j
- 官方二进制包归档:https://archive.apache.org/dist/xerces/j/binaries/