
本文介绍如何在 spring batch 中高效、可靠地处理同一目录下多个 json 文件(如按国家/地区分组的公司数据),通过为每个文件创建独立 job 实例实现天然的并行读取与故障隔离,规避单 step 多 reader 的限制。
在 Spring Batch 中,一个 Step 确实不支持配置多个 Reader 实例——ItemReader 是 Step 作用域内单例组件,且框架设计上要求每个 Step 仅绑定一个 Reader、一个 Processor 和一个 Writer。因此,试图在单 Step 内“动态切换 Reader”或“并发启动多个 Reader”不仅违背架构约束,还会导致上下文混乱、事务边界模糊及难以调试的问题。
但您的实际需求——按优先级顺序(SG > MY,alternate_id.json 先于主文件)并发读取多个文件,并各自写入数据库——完全可通过更符合 Spring Batch 哲学的方式优雅实现:将“每个文件”视为一个独立的、可识别的 Job 执行单元。
✅ 推荐方案:One File, One Job Instance
核心思路是:不再用 MultiResourcePartitioner 在单 Step 内调度多个资源,而是为每个目标文件启动一个独立的 Job 实例,并利用 JobParameters 唯一标识该实例(例如传入 input.file.path=/data/sg_company_group_alternate_id.json)。示例如下:
// 启动单个文件 Job 的服务方法
public void launchJobForFile(String filePath) throws Exception {
JobParameters params = new JobParametersBuilder()
.addString("input.file.path", filePath)
.addLong("timestamp", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(fileProcessingJob, params);
}对应的 Job 配置(Java Config)可定义为:
@Bean
public Job fileProcessingJob(JobBuilderFactory jobs, StepBuilderFactory steps) {
return jobs.get("fileProcessingJob")
.start(fileReadingStep(steps))
.build();
}
@Bean
public Step fileReadingStep(StepBuilderFactory steps) {
return steps.get("fileReadingStep")
.chunk(100)
.reader(jsonFileItemReader(null)) // reader 支持运行时注入路径
.processor(yourProcessor())
.writer(databaseItemWriter())
.build();
}
// 关键:Reader 从 JobParameters 动态获取文件路径
@Bean
@StepScope
public ItemReader jsonFileItemReader(@Value("#{jobParameters['input.file.path']}") String filePath) {
return new JsonItemReaderBuilder()
.jsonObjectReader(new JacksonJsonObjectReader<>(JsonNode.class))
.resource(new FileSystemResource(filePath))
.name("jsonReader")
.build();
} ? 注意:@StepScope + @Value("#{jobParameters[...]}") 是实现“每 Job 实例绑定专属资源”的关键,确保不同 Job 实例使用不同文件,互不干扰。
✅ 优势总结
- 天然并行:多个 Job 实例可由 TaskExecutor(如 ThreadPoolTaskExecutor)并发执行,无需 Partitioner;
- 精准容错:任一文件处理失败(如 JSON 格式错误、DB 连接超时),仅需重启对应 JobInstance,其余文件不受影响;
- 顺序可控:您可在调度层(如定时任务或自定义启动器)严格控制启动顺序——先遍历 SG 目录下的 *_alternate_id.json,再主文件;再切至 MY 目录,完全满足业务排序要求;
- 监控友好:每个 Job 实例在 BATCH_JOB_INSTANCE 表中独立记录,便于追踪、统计和审计。
⚠️ 注意事项
- 确保 JobParameters 中包含足够唯一性的参数(推荐至少含 input.file.path + 时间戳),避免因参数重复导致 JobInstanceAlreadyCompleteException;
- 若文件量极大(如数千个),需评估 JobRepository 性能及数据库连接池负载,必要时启用分页查询或异步批量提交;
- 不要将 JobLauncher 直接暴露给高并发 Web 请求,建议封装在消息队列(如 Kafka/RabbitMQ)或调度任务中驱动,保障系统稳定性。
综上,放弃“单 Step 多 Reader”的技术执念,转而拥抱 Spring Batch “Job as Unit of Work”的设计理念,不仅能彻底解决您的并发与顺序问题,更能显著提升系统的可维护性、可观测性与弹性恢复能力。










