使用 Object-XML 映射器编组 XML (Marshalling XML by Using Object-XML Mappers)
本章介绍 Spring 的对象-XML 映射(Object-XML Mapping,简称 O-X mapping)支持。O-X 映射是指将 XML 文档与对象相互转换的过程。这一转换过程也被称为 XML 编组(Marshalling)或 XML 序列化(Serialization)。
在 O-X 映射领域:
- Marshaller(编组器):负责将对象(图)序列化为 XML。
- Unmarshaller(解组器):负责将 XML 反序列化为对象图。
Spring OXM 的优势
使用 Spring 进行 O-X 映射的一些好处包括:
- 易于配置:Spring 的 Bean 工厂使得配置编组器变得非常容易,无需手动创建 JAXB 上下文、JiBX 绑定工厂等。你可以像配置应用中的其他任何 Bean 一样配置编组器。此外,许多编组器还提供基于 XML 命名空间的配置,使配置更加简单。
- 一致的接口:Spring 的 O-X 映射通过两个全局接口运行:
Marshaller和Unmarshaller。这些抽象让你能以相对较低的成本切换 O-X 映射框架,而无需修改执行编组的类。这种方法还有一个额外的好处,即可以非侵入式地混合使用不同的编组技术(例如,一部分编组使用 JAXB,另一部分使用 XStream)。 - 一致的异常体系:Spring 将底层 O-X 映射工具的异常转换为其自身的异常体系,以
XmlMappingException为根异常。这些运行时异常包装了原始异常,因此不会丢失任何信息。
Marshaller 和 Unmarshaller
理解 Marshaller
Spring 将所有编组操作抽象在 org.springframework.oxm.Marshaller 接口之后。
public interface Marshaller {
/**
* 将给定的对象图编组到提供的 Result 中。
*/
void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}Result 是一个标记接口,代表 XML 输出的抽象。常见的实现包括:
| Result 实现 | 包装的 XML 表示 |
|---|---|
DOMResult | org.w3c.dom.Node |
SAXResult | org.xml.sax.ContentHandler |
StreamResult | java.io.File, java.io.OutputStream, 或 java.io.Writer |
理解 Unmarshaller
与之对应的是 org.springframework.oxm.Unmarshaller 接口。
public interface Unmarshaller {
/**
* 将提供的 Source 解组为一个对象图。
*/
Object unmarshal(Source source) throws XmlMappingException, IOException;
}Source 也是一个抽象接口,其实现包括:
| Source 实现 | 包装的 XML 表示 |
|---|---|
DOMSource | org.w3c.dom.Node |
SAXSource | org.xml.sax.InputSource 和 org.xml.sax.XMLReader |
StreamSource | java.io.File, java.io.InputStream, 或 java.io.Reader |
使用示例
以下示例演示了如何编组和解组一个简单的 Settings JavaBean。
public class Application {
private static final String FILE_NAME = "settings.xml";
private Settings settings = new Settings();
private Marshaller marshaller;
private Unmarshaller unmarshaller;
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public void saveSettings() throws IOException {
try (FileOutputStream os = new FileOutputStream(FILE_NAME)) {
this.marshaller.marshal(settings, new StreamResult(os));
}
}
public void loadSettings() throws IOException {
try (FileInputStream is = new FileInputStream(FILE_NAME)) {
this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
}
}
}class Application {
var settings = Settings()
lateinit var marshaller: Marshaller
lateinit var unmarshaller: Unmarshaller
fun saveSettings() {
FileOutputStream(FILE_NAME).use { os ->
marshaller.marshal(settings, StreamResult(os))
}
}
fun loadSettings() {
FileInputStream(FILE_NAME).use { is ->
settings = unmarshaller.unmarshal(StreamSource(is)) as Settings
}
}
}支持的编组技术
JAXB
JAXB(Java Architecture for XML Binding)是 Java 标准的 XML 绑定技术。Spring 通过 Jaxb2Marshaller 提供支持。
<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="com.example.Flight"/>
</oxm:jaxb2-marshaller>XStream
XStream 是一个简单的库,用于将对象序列化为 XML 及其反向过程。它不需要任何映射,生成简洁的 XML。
安全警告
默认情况下,XStream 允许解组任意类,这可能导致不安全的 Java 序列化攻击。不建议使用 XStreamMarshaller 处理来自外部源(如 Web 流量)的 XML。如果必须使用,请设置 supportedClasses 属性以限制可处理的类。
补充教学
1. XML 还在流行吗?XML 编组的应用场景
虽然现代 Web 开发中 JSON 已成为主流,但 XML 编组在以下场景中依然至关重要:
- Web Services (SOAP):SOAP 协议完全基于 XML,Spring OXM 可以很好地集成到 Spring Web Services 中。
- 行业标准:金融(如 ISO 20022)、电信和政府系统仍广泛使用 XML 作为交互格式。
- 配置文件:一些桌面或企业应用仍选择使用 XML 存储复杂的层次化配置。
2. JAXB 在 Java 11+ 中的变化
在 Java 8 之后,JAXB 已不再随 JDK 一起发布。如果你使用的是现代 JDK,你需要手动引入依赖:
- Maven 坐标:早期是
javax.xml.bind:jaxb-api,现在已迁移到 Jakarta EE 命名空间jakarta.xml.bind:jakarta.xml.bind-api。 - Spring 支持:Spring 6+ 全面支持
jakarta命名空间。
3. XML 安全性 (XXE 攻击)
在处理 XML 时,安全性不容忽视。常见的威胁是 XML 外部实体(XXE)攻击。
- Spring 的保护:Spring 的编组器默认通常会禁用 DTD 声明和外部实体的处理,以降低风险。但如果你使用的是底层原始解析器,务必确保手动关闭相关功能,防止恶意 XML 导致的文件读取或 SSRF。