乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 批处理概述与 Spring Batch 核心理念

    • Spring Batch 概述
    • Job-Instance-Execution 三层生命周期
    • 三层架构
    • Chunk 处理模型
    • Tasklet 处理模型
  • 第2章 Job与作业配置

    • Job 详解
    • Job 配置
    • JobLauncher 详解
    • JobParameters 详解
    • JobRepository 详解
  • 第3章 Step与执行模型

    • Step 详解
    • Step 配置
    • ExecutionContext 详解
    • ItemStream 与状态管理
    • StepScope 与 JobScope
  • 第4章 ItemReader数据读取

    • ItemReader 详解
    • FlatFileItemReader 详解
    • JdbcItemReader 详解
    • MultiResourceItemReader 详解
  • 第5章 ItemProcessor 数据处理

    • ItemProcessor 详解
  • 第6章 ItemWriter 数据写出

    • ItemWriter 详解
    • FlatFileItemWriter 详解
    • CompositeItemWriter 详解
    • JdbcBatchItemWriter 详解
  • 第7章 Chunk 处理与事务边界

    • Chunk 处理模型详解
    • 事务边界
  • 第8章 作业参数与启动

    • 命令行与 Web 启动
  • 第9章 监听器与拦截器

    • 监听器详解
  • 第10章 重启重试与跳过策略

    • 重启与重试
    • 跳过策略
  • 第11章 作业流与条件决策

    • 作业流与条件决策
  • 第12章 分区与并行处理

    • 分区详解
    • 并行 Step 与 Split
  • 第13章 与 Spring Boot 集成实践

    • Spring Boot 集成
  • 第15章 运维与监控

    • 大作业设计模式
    • 运维与监控

MultiResourceItemReader 详解

本章定位:掌握如何用 MultiResourceItemReader 聚合多个文件,配合通配符和排序策略实现多文件批处理。

定义与作用

MultiResourceItemReader 是一个包装器 Reader,它将多个 Resource(文件)视为一个逻辑数据源,依次委托给内部的 ItemReader 逐文件读取。读完一个文件后自动切换到下一个,对下游完全透明。

飞翔科技运营部高英经常一次发来多个 CSV 文件(orders_20260613_1.csv、orders_20260613_2.csv...),小崔用 MultiResourceItemReader 一行代码解决:

"MultiResourceItemReader 就像一个自动换碟机——你给它一堆唱片(文件),它会一张一张放完,中间不需要你手动切换。"

核心原理

完整示例

场景一:飞翔科技——多分片订单文件聚合处理

背景:运营部杨英从 ERP 系统导出订单数据时,系统自动拆分为多个文件,需要统一处理。

@Bean
@StepScope
public MultiResourceItemReader<Order> multiOrderReader(
        @Value("file:/data/orders/orders_*.csv") Resource[] resources) {

    // 内部委托的 FlatFileItemReader
    FlatFileItemReader<Order> delegate = new FlatFileItemReaderBuilder<Order>()
            .name("orderDelegateReader")
            .delimited()
            .names("orderId", "customerName", "amount", "orderDate")
            .targetType(Order.class)
            .linesToSkip(1)
            .build();

    MultiResourceItemReader<Order> reader = new MultiResourceItemReader<>();
    reader.setName("multiOrderReader");
    reader.setResources(resources);   // 多个文件
    reader.setDelegate(delegate);     // 委托读取器
    reader.setStrict(false);          // 部分文件不存在不抛异常
    reader.setSaveState(true);        // 支持断点续传(记录当前文件索引)
    return reader;
}

场景二:使用 PathMatchingResourcePatternResolver 动态发现文件

@Bean
public MultiResourceItemReader<Student> dynamicMultiReader() throws IOException {
    PathMatchingResourcePatternResolver resolver =
            new PathMatchingResourcePatternResolver();

    // 自动扫描 /data/students/ 下所有 CSV 文件
    Resource[] resources = resolver.getResources(
            "file:/data/students/*.csv");

    // 按文件名排序,确保处理顺序一致
    Arrays.sort(resources, Comparator.comparing(Resource::getFilename));

    FlatFileItemReader<Student> delegate = new FlatFileItemReaderBuilder<Student>()
            .name("studentDelegate")
            .delimited()
            .names("studentId", "name", "age")
            .targetType(Student.class)
            .build();

    MultiResourceItemReader<Student> reader = new MultiResourceItemReader<>();
    reader.setName("dynamicMultiReader");
    reader.setResources(resources);
    reader.setDelegate(delegate);
    reader.setSaveState(true);
    return reader;
}

操作前后对比:

操作前:手动循环文件
  String[] files = {"orders_1.csv", "orders_2.csv", "orders_3.csv"};
  for (String file : files) {
      BufferedReader br = new BufferedReader(new FileReader(file));
      // ... 手动读行、处理、跟踪进度
  }
  崩溃后:无法知道当前处理到哪个文件的哪一行

操作后:MultiResourceItemReader
  框架自动按序处理所有文件,saveState 记录 (fileIndex, lineNumber)
  崩溃后自动从上次中断的文件和行号恢复

易错场景与避坑

反例一:委托 Reader 不是 prototype 作用域

// ❌ 委托 Reader 是单例 → 第二次使用时状态残留
@Bean
public FlatFileItemReader<Order> delegateReader() {
    return new FlatFileItemReaderBuilder<Order>()
            .name("reader")
            .resource(...) // 单例模式下 resource 固定
            .build();
}

@Bean
public MultiResourceItemReader<Order> reader() {
    MultiResourceItemReader<Order> mr = new MultiResourceItemReader<>();
    mr.setDelegate(delegateReader()); // ❌ 单例 delegate
    return mr;
}

正确做法:MultiResourceItemReader 每次切换文件时会调用 delegate.close() 和 delegate.open(executionContext),delegate 无需是 prototype。但需要确保 delegate 支持 ItemStream 接口(FlatFileItemReader 默认实现)。

反例二:忘记设置 saveState=true

// ❌ saveState=false → 崩溃后从头处理所有文件
reader.setSaveState(false);

面试高频考点

Q1:MultiResourceItemReader 如何实现断点续传?

它通过 ExecutionContext 保存两个关键值:CurrentResource(当前文件索引)和委托 Reader 的 ExecutionContext(文件内行号)。重启时恢复这两个值,继续处理。

Q2:和 FlatFileItemReader 直接读大文件相比,MultiResourceItemReader 的优势?

1)支持通配符动态发现文件(新增文件自动纳入);2)按文件名排序保证处理顺序;3)单个文件损坏不影响其他文件;4)并行处理时可以按文件粒度分片。


上一章:JdbcItemReader 详解下一章:ItemProcessor 详解

上一页
JdbcItemReader 详解