以下内容是来自 Spring Framework 官方文档 的一个章节,标题为:
5. Marshalling XML by Using Object-XML Mappers(使用对象-XML 映射器进行 XML 编组)
这个章节系统地介绍了 Spring 框架中如何通过 O-X Mapping(Object-XML Mapping,对象与 XML 的映射) 技术来实现 Java 对象和 XML 数据之间的相互转换。这种技术在现代开发中虽然不如 JSON 流行,但在一些遗留系统、Web 服务(如 SOAP)、配置文件处理等场景中仍然非常重要。
🌟 整体理解:这是讲什么的?
简单来说,这一章讲的是:
如何用 Spring 框架把 Java 对象变成 XML(序列化/编组),以及把 XML 变回 Java 对象(反序列化/解组)。
这类似于我们熟悉的 Jackson 或 Gson 处理 JSON,只不过这里是处理 XML。
🔍 分节详解
5.1 Introduction(简介)
核心概念:
- Marshalling(编组 / 序列化):将 Java 对象 → 转成 XML。
- Unmarshalling(解组 / 反序列化):将 XML → 转成 Java 对象。
- 这两个操作合起来叫 O-X Mapping(对象-XML 映射)。
Spring 做了哪些事?
- ✅ 简化配置
不用手动 new JAXBContext、JiBX BindingFactory 等底层对象,直接像普通 Bean 一样注入即可。 - ✅ 统一接口
所有 O-X 工具都实现了Marshaller和Unmarshaller接口,可以轻松切换不同技术(比如从 JAXB 换到 XStream)。 - ✅ 统一异常体系
所有底层异常都被包装成 Spring 的运行时异常XmlMappingException,避免检查异常污染代码。
5.2 Marshaller 和 Unmarshaller 接口
这两个是 Spring 提供的核心接口。
5.2.1 Marshaller 接口
java
void marshal(Object graph, Result result) throws XmlMappingException, IOException;
作用:把一个 Java 对象写入到 XML 输出目标(Result)。
Result 实现类 |
包装的输出形式 |
|---|---|
DOMResult |
W3C DOM Node(内存中的 XML 树) |
SAXResult |
SAX ContentHandler(事件驱动) |
StreamResult |
文件、OutputStream、Writer |
⚠️ 注意:不是所有类都能随便传进去!必须被"映射"过(加注解、注册类、或有 schema 支持)。
5.2.2 Unmarshaller 接口
java
Object unmarshal(Source source) throws XmlMappingException, IOException;
作用:从 XML 输入源读取并还原成 Java 对象。
Source 实现类 |
包装的输入形式 |
|---|---|
DOMSource |
DOM Node |
SAXSource |
InputSource + XMLReader |
StreamSource |
File、InputStream、Reader |
💡 大多数实现类同时实现了
Marshaller和Unmarshaller,所以一个 bean 可以既用于序列化又用于反序列化。
5.2.3 XmlMappingException
Spring 将各种 O-X 工具(JAXB、XStream 等)抛出的原始异常统一转换为自己的异常树,根节点就是 XmlMappingException。
这样你在业务代码里只需要捕获一种异常类型,不用关心底层用了哪种工具。
子类还有:
MarshallingFailureExceptionUnmarshallingFailureException
便于区分错误发生在哪个阶段。
5.3 使用示例:保存/加载设置
这是一个完整的例子,展示如何用 Spring OXM 来持久化应用设置。
示例结构:
java
class Settings {
private boolean fooEnabled;
// getter/setter
}
java
class Application {
private Settings settings = new Settings();
private Marshaller marshaller;
private Unmarshaller unmarshaller;
public void saveSettings() throws IOException {
try (FileOutputStream os = new FileOutputStream("settings.xml")) {
marshaller.marshal(settings, new StreamResult(os));
}
}
public void loadSettings() throws IOException {
try (FileInputStream is = new FileInputStream("settings.xml")) {
settings = (Settings) unmarshaller.unmarshal(new StreamSource(is));
}
}
}
配置文件 applicationContext.xml:
xml
<bean id="application" class="Application">
<property name="marshaller" ref="xstreamMarshaller"/>
<property name="unmarshaller" ref="xstreamMarshaller"/>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
输出结果:
xml
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
✅ 特点:无需任何额外配置(XStream 默认支持 POJO),非常方便快速上手。
5.4 XML 配置命名空间(oxm namespace)
为了更简洁地配置 marshaller,Spring 提供了 <oxm:xxx> 标签。
需要先引入命名空间:
xml
<beans xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="
http://www.springframework.org/schema/oxm
https://www.springframework.org/schema/oxm/spring-oxm.xsd">
然后可以用简写方式创建 marshaller:
JAXB 示例:
xml
<oxm:jaxb2-marshaller id="marshaller" contextPath="org.example.schema"/>
等价于:
xml
<bean class="Jaxb2Marshaller">
<property name="contextPath" value="..."/>
</bean>
5.5 JAXB(Java Architecture for XML Binding)
JAXB 是标准的 Java XML 绑定方案,支持通过注解或 XSD 自动生成类。
Jaxb2Marshaller
- 实现了
Marshaller和Unmarshaller - 必须指定
contextPath(包名列表)或classesToBeBound
配置方式一:通过 contextPath
xml
<bean class="Jaxb2Marshaller">
<property name="contextPath" value="com.example.model"/>
</bean>
配置方式二:显式列出类
xml
<bean class="Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.example.Flight</value>
<value>com.example.Flights</value>
</list>
</property>
</bean>
还可以加上 XSD 校验:
xml
<property name="schema" value="classpath:schema.xsd"/>
✅ 优点:标准、稳定、适合 Web Services(SOAP)
❌ 缺点:配置略复杂,性能一般
5.6 JiBX
JiBX 是一种基于字节码增强的技术,类似 Hibernate 对数据库的操作。
- 先定义 binding.xml 描述映射规则
- 编译后用 JiBX 工具"增强"class 文件,插入序列化逻辑
- 性能高、生成的 XML 干净
JibxMarshaller
每个实例只能处理一个类(由 targetClass 指定)
xml
<bean class="JibxMarshaller">
<property name="targetClass" value="org.example.Flights"/>
</bean>
如果要处理多个类,就得配多个 JibxMarshaller。
✅ 优点:速度快、控制精细
❌ 缺点:需额外构建步骤(字节码增强),学习成本较高
5.7 XStream
XStream 是最简单的 XML 序列化库之一,不需要注解也不需要 mapping 文件。
XStreamMarshaller
开箱即用,配置极少:
xml
<bean id="xstream" class="XStreamMarshaller"/>
可选配置别名(让 XML 更友好):
xml
<property name="aliases">
<props>
<prop key="Flight">org.example.Flight</prop>
</props>
</property>
⚠️ 重要安全警告:
XStream 默认允许反序列化任意类,容易导致 远程代码执行漏洞(RCE)!
✅ 正确做法:限制只允许特定类反序列化:
xml
<property name="supportedClasses" value="org.example.Flight"/>
或者注册自定义 converter,禁用默认行为。
✅ 优点:简单、易用、POJO 友好
❌ 缺点:安全性差(外部输入慎用)、不支持命名空间(不适合 Web Service)
✅ 总结对比表
| 技术 | 是否需要注解/mapping | 性能 | 安全性 | 适用场景 |
|---|---|---|---|---|
| JAXB | 是(或 XSD) | 中等 | 高 | Web Services、企业级系统 |
| JiBX | 是(binding.xml) | 高 | 高 | 高性能 XML 处理 |
| XStream | 否(自动探测) | 中 | 低(默认) | 内部配置文件、测试 |
🧠 如何选择?
| 场景 | 推荐方案 |
|---|---|
| 使用 SOAP Web Service | ✅ JAXB(标准兼容) |
| 内部配置文件读写 | ✅ XStream(简单快捷) |
| 高频 XML 处理(大批量) | ✅ JiBX(高性能) |
| 外部不可信 XML 输入 | ❌ 避免 XStream;✅ 用 JAXB + Schema 校验 |
🛡️ 安全提醒(特别重要!)
⚠️ 永远不要对来自外部用户或网络的 XML 使用 XStream 进行 unmarshal!
除非你明确设置了
supportedClasses或自定义了安全的 Converter。
否则攻击者可以通过构造恶意 XML 触发 RCE(远程代码执行),造成严重安全风险。
📚 学习建议
- 如果你是初学者 → 先试 XStream,体验 OXM 的基本流程。
- 如果做企业项目或 Web Service → 学 JAXB。
- 如果追求极致性能 → 看 JiBX。
- 所有情况下 → 理解
Marshaller和Unmarshaller接口的设计思想。
如果你希望我帮你:
- 写一个完整的 Maven 示例?
- 演示如何用 JAXB 注解标注类?
- 把上面的例子改成 Java Config(非 XML)?
- 解释某个具体类的作用?
欢迎继续提问 😊