
本文介绍如何在 spring batch 中高效处理同一目录下多个 json 文件(如按国家/地区和类型排序),通过“每文件一作业实例”策略实现真正并行读取与写入,兼顾顺序控制、可扩展性与容错能力。
在 Spring Batch 中,一个 Step 内确实不支持多个 Reader 实例同时运行——这是框架设计的基本约束:每个 Step 绑定唯一 ItemReader,其生命周期与 Step 强耦合。因此,试图在单 Step 内动态切换或并发启动多个 Reader(如为每个 JSON 文件分配独立 Reader)不仅违背模型语义,还会引发状态冲突、事务边界混乱及难以调试的竞态问题。
正确的解法是转变粒度:从“单作业多文件”升级为“多作业实例,每实例处理单文件”。这并非绕过限制,而是遵循 Spring Batch 的核心哲学——以作业(Job)为最小可调度、可追踪、可恢复的执行单元。
✅ 推荐方案:基于 Job Parameter 的文件级作业实例化
将每个待处理文件路径作为唯一标识性 Job Parameter(如 inputFile=/data/company_group/sg_company_group_alternate_id.json),配合 JobParametersIncrementer 确保每次启动生成新实例:
// 启动作业示例(如在 Controller 或 Scheduler 中)
JobParameters params = new JobParametersBuilder()
.addString("inputFile", "/data/company_group/sg_company_group_alternate_id.json")
.addLong("timestamp", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(fileProcessingJob, params);对应地,定义一个泛化 Job:
<!-- job-config.xml -->
<job id="fileProcessingJob" job-repository="jobRepository">
<step id="processSingleFile">
<tasklet transaction-manager="transactionManager">
<chunk reader="jsonFileItemReader" writer="jpaItemWriter"
commit-interval="100"/>
</tasklet>
</step>
</job>其中 jsonFileItemReader 是参数化 Reader:
@Bean
@StepScope
public JsonItemReader<CompanyGroup> jsonFileItemReader(
@Value("#{jobParameters['inputFile']}") String inputFile) {
JsonItemReader<CompanyGroup> reader = new JsonItemReader<>();
reader.setResource(new FileSystemResource(inputFile));
reader.setJsonObjectReader(new JacksonJsonObjectReader<>(CompanyGroup.class));
reader.setLinesToSkip(1); // 如需跳过 header
return reader;
}? 顺序控制与批量触发
虽然作业实例彼此独立,但你仍可通过外部逻辑保障执行顺序:
- 预排序 + 串行提交:在调度层(如 @Scheduled 方法)中,先按规则(SG 优先、alternate_id 优先)对文件列表排序,再逐个调用 jobLauncher.run();
- 并行提交 + 依赖调度:若需 SG 文件全部完成后再启动 MY 文件,可使用 CountDownLatch 或消息队列(如 Kafka)作为协调机制;
- 元数据驱动:将文件清单与状态存入数据库,由 Quartz 定时扫描待处理文件并触发对应作业。
⚠️ 注意事项与最佳实践
- 避免共享资源竞争:确保 ItemWriter(如 JPA Repository)线程安全,推荐使用无状态写入器,或为每个作业实例配置独立事务管理器;
- 参数必须为 IDENTIFYING:inputFile 参数需设为 identifying(默认行为),否则 Spring Batch 会视为同一作业实例重复执行;
- 监控与可观测性:利用 JobExplorer 查询各实例状态,结合 Actuator Endpoint 暴露作业指标;
- 错误隔离:单个文件解析失败(如 JSON 格式错误)仅导致该作业实例失败,其余文件不受影响,重试成本极低。
综上,放弃“单 Step 多 Reader”的设想,拥抱“每文件一作业”的范式,不仅能自然解决并发读取问题,更带来弹性伸缩、精准重试、清晰追踪等企业级优势——这才是 Spring Batch 在真实场景中的正确打开方式。










