本章将介绍如何使用 Spring Batch4 中的 StaxEventItemReader 类从 XML 文件读取数据。StaxEventItemReader 是 Spring Batch4 提供的 XML 文件读取器,基于 StAX (Streaming API for XML) 解析技术。它高效处理大型 XML 文件,支持流式解析,避免将整个文件加载到内存中,特别适合处理 GB 级 XML 数据文件。
与 DOM 解析器不同,StAX 采用流式处理方式,逐行读取 XML 文档,无需将整个文档加载到内存中,因此内存占用极低。
大型XML文件 → StaxEventItemReader → 流式解析 → 内存高效 → 分块处理 → 数据库/文件写入
StaxEventItemReader 核心特性如下:
基于事件驱动:通过 START_ELEMENT 和 END_ELEMENT 事件定位目标数据
支持 XPath 表达式:精确定位需要解析的元素
可配置的解组器:将 XML 元素映射为 Java 对象
事务支持:读取位置在事务回滚时自动恢复
线程安全:可在多线程环境中使用
StaxEventItemReader 使用场景如下:
从 XML 文件导入数据到数据库
处理 SOAP 消息或 Web 服务响应
转换企业级 XML 数据格式
处理医疗/金融行业标准 XML(如 HL7、FIXML)
setResource(Resource resource) 设置要读取的 XML 文件资源。示例:
reader.setResource(new ClassPathResource("data/users.xml"));
setFragmentRootElementName(String name) 指定作为单个记录的根元素标签名(如 <user>)。示例:
reader.setFragmentRootElementName("user");
setFragmentRootElementNames(String[] names) 指定多个根元素标签名(处理多种类型的记录)。示例:
reader.setFragmentRootElementNames(new String[] { "user", "admin" });
setUnmarshaller(Unmarshaller unmarshaller) 设置 XML 到 Java 对象的解组器,支持的解组器:
(1)Jaxb2Marshaller(基于 JAXB 注解)
(2)XStreamMarshaller(灵活的别名配置)
示例:
Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setClassesToBeBound(User.class); reader.setUnmarshaller(marshaller);
setSaveState(boolean saveState) 是否保存读取状态(用于作业重启时恢复进度),默认值为 true。示例:
reader.setSaveState(true);
setCurrentItemCount(int count) 设置起始记录索引(用于断点恢复),示例:
reader.setCurrentItemCount(100); // 从第101条记录开始
setMaxItemCount(int count) 设置最大处理记录数,示例:
reader.setMaxItemCount(1000); // 最多处理1000条记录
setNamespaceAware(boolean namespaceAware) 是否处理 XML 命名空间,默认值为 false。示例:
reader.setNamespaceAware(true);
setStrict(boolean strict) 文件不存在时是否抛出异常,默认值为 true。示例:
reader.setStrict(false); // 文件不存在时返回空读取器
setRecordSeparatorPolicy(RecordSeparatorPolicy policy) 自定义记录分隔策略,示例:
reader.setRecordSeparatorPolicy(new MyCustomRecordSeparatorPolicy());
afterPropertiesSet() 初始化读取器(检查必要配置)。注意,实现了 InitializingBean 接口,Spring 会自动调用 。
open(ExecutionContext executionContext) 打开资源并准备读取(由 Spring Batch 框架调用)。
read() 读取下一条记录(返回 null 表示读取结束)。
update(ExecutionContext executionContext) 更新执行上下文(保存当前读取位置)。
setSkippedItemsCallback(SkippedItemsCallback<T> callback) 设置跳过记录时的回调。示例:
reader.setSkippedItemsCallback((item, exception) -> { log.warn("Skipped item: {}", item, exception); });
由于使用 StaxEventItemReader 读取 XML 文件,需要单独引入 spring-oxm 和 xstream 依赖,如下:
<!-- 从XML读取数据,StaxEventItemReader 需要依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency>
创建一个名为 users.xml 的 XML 文件,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <users> <user> <id>1</id> <username>张三</username> <password>13BC03AC29FAC7B29736EC3BE5C2F55A</password> </user> <user> <id>2</id> <username>李四</username> <password>5E5994FBCFA922D804DF45295AE98604</password> </user> <user> <id>3</id> <username>王五</username> <password>6C14DA109E294D1E8155BE8AA4B1CE8E</password> </user> <user> <id>4</id> <username>赵六</username> <password>03774AD7979A5909E78F9C9DB3A2F0B2</password> </user> </users>
创建一个名为 User 的实体,用来映射 users 表,代码如下:
package com.hxstrive.spring_batch.staxEventItemReaderDemo.dto; import lombok.Data; import lombok.ToString; /** * 用户DTO * @author hxstrive.com * @since 1.0.0 2025/5/20 17:33 */ @Data @ToString public class User { private int id; private String username; private String password; }
记得引入 lombok 的依赖。
使用 @Configuration 注解创建一个名为 BatchConfig 的配置类,使用 StaxEventItemReader 类读取 XML 文件,代码如下:
package com.hxstrive.spring_batch.staxEventItemReaderDemo.config; import com.hxstrive.spring_batch.staxEventItemReaderDemo.dto.User; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.xml.StaxEventItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.oxm.xstream.XStreamMarshaller; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Spring Batch 配置类 * @author hxstrive.com * @since 1.0.0 2025/5/12 14:07 */ @Configuration public class BatchConfig { // 用于创建和配置 Job 对象的工厂类 @Autowired private JobBuilderFactory jobBuilderFactory; // 用于创建和配置 Step 对象的工厂类 @Autowired private StepBuilderFactory stepBuilderFactory; // 创建Job对象 @Bean public Job staxEventItemReaderDemoJob() { return jobBuilderFactory.get("staxEventItemReaderDemoJob" + System.currentTimeMillis()) .start(staxEventItemReaderDemoStep()) .build(); } // 创建Step对象 @Bean public Step staxEventItemReaderDemoStep() { return stepBuilderFactory.get("staxEventItemReaderDemoStep") .<User, User>chunk(2) .reader(staxEventItemReader()) .writer(new ItemWriter<User>() { @Override public void write(List<? extends User> list) throws Exception { System.out.println(Arrays.toString(list.toArray())); } }) .build(); } // 创建ItemReader对象,使用 JdbcPagingItemReader 实现从数据库读取数据 @Bean @StepScope //将 Bean 的生命周期与 Step 执行上下文 绑定 public StaxEventItemReader<? extends User> staxEventItemReader() { StaxEventItemReader<User> reader = new StaxEventItemReader<>(); reader.setResource(new ClassPathResource("users.xml")); // 指定需要处理的根标签 reader.setFragmentRootElementName("user"); // 把XML转换成对象 XStreamMarshaller marshaller = new XStreamMarshaller(); Map<String,Class<? extends User>> map = new HashMap<>(); map.put("user", User.class); marshaller.setAliases(map); reader.setUnmarshaller(marshaller); return reader; } }
上述代码详细说明:
XStreamMarshaller 是一个关键的 XML 数据处理组件,主要用于将 XML 格式的数据转换为 Java 对象(反序列化),以及将 Java 对象转换回 XML(序列化)。它基于 XStream 库实现,提供了灵活且无需大量注解的对象映射方式。
运行示例,观察输出日志,看见用户信息成功被读取,如下图: