
本文介绍如何在 spring batch 中高效处理同一目录下多个 json 文件(如按国家/地区及类型排序),通过“每文件一作业实例”策略实现真正并行读取与写入,兼顾顺序控制、可扩展性与故障隔离。
在 Spring Batch 中,一个 Step 仅允许配置一个 ItemReader,这是框架的核心设计约束——它保障了步骤级事务一致性与状态可追踪性。因此,试图在单个 Step 内“动态切换多个 Reader 实例”或“让一个 Step 并行消费多个资源”本质上违背了批处理模型,不仅无法原生支持,强行绕过(如自定义 Reader 封装多资源迭代)还会导致事务边界模糊、重启语义失效、监控粒度粗化等严重问题。
✅ 正确且推荐的解决方案是:采用“一个文件 → 一个 Job 实例”的设计范式。即不追求“单 Job 多 Reader”,而是将每个待处理文件(如 sg_company_group_alternate_id.json)作为独立的、可识别的 Job 执行单元。
✅ 实现步骤概览
-
预扫描并排序文件列表(满足业务顺序要求)
在触发批量执行前,使用 ResourcePatternResolver 或 Files.walk() 扫描目标目录,并按规则排序:- 优先级:sg_* > my_*
- 同国家内:*_alternate_id.json > *.json
List
sortedFiles = Files.walk(Paths.get("company_group")) .filter(Files::isRegularFile) .filter(p -> p.toString().endsWith(".json")) .sorted((p1, p2) -> { String n1 = p1.getFileName().toString(); String n2 = p2.getFileName().toString(); // 先按国家分组(sg > my) int countryCmp = compareCountry(n1, n2); if (countryCmp != 0) return countryCmp; // 再按是否为 alternate_id 排序 boolean alt1 = n1.contains("_alternate_id"); boolean alt2 = n2.contains("_alternate_id"); return Boolean.compare(alt2, alt1); // alternate 优先 }) .collect(Collectors.toList()); -
为每个文件启动独立 Job 实例
使用唯一标识参数(如 input.file.path)构建 JobParameters,确保每个 Job 实例可区分、可重启:for (Path file : sortedFiles) { JobParameters params = new JobParametersBuilder() .addString("input.file.path", file.toUri().toString()) .addLong("run.time", System.currentTimeMillis()) .toJobParameters(); jobLauncher.run(job, params); } -
在 Job 配置中注入文件路径并构建 Reader
利用 @Value("#{jobParameters['input.file.path']}") 动态注入路径,在 @Bean 中创建 FlatFileItemReader(或 JsonItemReader):@Bean public JsonItemReader
reader( @Value("#{jobParameters['input.file.path']}") String filePath) { return new JsonItemReaderBuilder () .jsonObjectReader(new JacksonJsonObjectReader<>(CompanyGroup.class)) .resource(new UrlResource(URI.create(filePath))) .name("companyGroupReader") .build(); }
⚠️ 注意事项与最佳实践
- 无需 Partitioner:该方案天然规避了 MultiResourcePartitioner 的复杂性与单 Step 瓶颈,每个 Job 实例独占 Reader/Writter/Transaction。
- 并行执行:配合 TaskExecutor(如 SimpleAsyncTaskExecutor 或线程池)与 JobLauncher,可轻松实现多文件并发处理。
- 精准重启:任一文件处理失败,仅需重跑对应 JobParameters 的 Job,不影响其他文件。
- 监控友好:每个 Job 实例在 BATCH_JOB_EXECUTION 表中独立记录,便于按文件粒度审计、统计耗时、排查异常。
- 顺序保障(如需强顺序):若业务严格要求“SG alternate → SG main → MY alternate → MY main”串行执行,则在启动循环中同步调用 jobLauncher.run(...);若仅需逻辑分组优先级(如 SG 组整体早于 MY 组),可对排序后列表分组提交至线程池。
✅ 总结
与其在 Spring Batch 的单 Step 模型中“硬塞多个 Reader”,不如拥抱其“Job 为部署与调度基本单元”的设计理念。以文件为 Job 边界,辅以参数化配置与合理排序,不仅能自然满足您的读取顺序与并行需求,更能显著提升系统的健壮性、可观测性与运维效率。这是 Spring Batch 社区广泛验证的生产级实践模式。










