Spring OXM:轻松实现Java-XML互转

以下内容是来自 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 对象(反序列化/解组)。

这类似于我们熟悉的 JacksonGson 处理 JSON,只不过这里是处理 XML


🔍 分节详解

5.1 Introduction(简介)

核心概念:
  • Marshalling(编组 / 序列化):将 Java 对象 → 转成 XML。
  • Unmarshalling(解组 / 反序列化):将 XML → 转成 Java 对象。
  • 这两个操作合起来叫 O-X Mapping(对象-XML 映射)
Spring 做了哪些事?
  1. 简化配置
    不用手动 new JAXBContext、JiBX BindingFactory 等底层对象,直接像普通 Bean 一样注入即可。
  2. 统一接口
    所有 O-X 工具都实现了 MarshallerUnmarshaller 接口,可以轻松切换不同技术(比如从 JAXB 换到 XStream)。
  3. 统一异常体系
    所有底层异常都被包装成 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

💡 大多数实现类同时实现了 MarshallerUnmarshaller,所以一个 bean 可以既用于序列化又用于反序列化。

5.2.3 XmlMappingException

Spring 将各种 O-X 工具(JAXB、XStream 等)抛出的原始异常统一转换为自己的异常树,根节点就是 XmlMappingException

这样你在业务代码里只需要捕获一种异常类型,不用关心底层用了哪种工具。

子类还有:

  • MarshallingFailureException
  • UnmarshallingFailureException

便于区分错误发生在哪个阶段。


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
  • 实现了 MarshallerUnmarshaller
  • 必须指定 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 Security


📚 学习建议

  1. 如果你是初学者 → 先试 XStream,体验 OXM 的基本流程。
  2. 如果做企业项目或 Web Service → 学 JAXB
  3. 如果追求极致性能 → 看 JiBX
  4. 所有情况下 → 理解 MarshallerUnmarshaller 接口的设计思想。

如果你希望我帮你:

  • 写一个完整的 Maven 示例?
  • 演示如何用 JAXB 注解标注类?
  • 把上面的例子改成 Java Config(非 XML)?
  • 解释某个具体类的作用?

欢迎继续提问 😊

相关推荐
weixin_457340213 小时前
VOC XML 旋转框 转换为 YOLO OBB 格式
xml·yolo·目标检测·视觉检测
Lisonseekpan3 小时前
为什么要避免使用 `SELECT *`?
java·数据库·后端·sql·mysql·oracle
一只小透明啊啊啊啊3 小时前
Java的中间件
java·开发语言·中间件
Wilson Chen3 小时前
深入理解 MySQL 事务与锁机制:从 ACID 到 Next-Key Lock 的实证之旅
java·数据库·mysql
学编程就要猛3 小时前
数据结构初阶:Java中的ArrayList
java·开发语言·数据结构
JH30733 小时前
10分钟理解泛型的通配符(extends, super, ?)
java·开发语言·windows
在等晚安么4 小时前
力扣面试经典150题打卡
java·数据结构·算法·leetcode·面试·贪心算法
Fency咖啡4 小时前
Spring进阶 - Spring事务理论+实战,一文吃透事务
java·数据库·spring
Zxxxxxy_4 小时前
【MYSQL】增删改查
java·数据库·mysql