
本文介绍在 Spring Batch 中当 FlatFileItemReader 的输入文件不存在时,避免抛出 IllegalStateException 并实现无错误降级处理的完整方案,包括禁用 strict 模式、监听读取计数及自定义空数据逻辑。
本文介绍在 spring batch 中当 `flatfileitemreader` 的输入文件不存在时,避免抛出 `illegalstateexception` 并实现无错误降级处理的完整方案,包括禁用 strict 模式、监听读取计数及自定义空数据逻辑。
在 Spring Batch 中,FlatFileItemReader 默认以 strict 模式运行——即在作业启动阶段(open() 时)强制校验输入资源(如 CSV 文件)必须存在且可访问。若文件缺失,会立即抛出 IllegalStateException: Input resource must exist,导致整个 Job 失败。但实际业务中,常需支持“文件可选”场景:例如定时任务中上游未准时生成文件,此时应跳过读取、写入默认/占位内容,而非中断流程。
✅ 正确解决方案:两步走
1. 禁用 strict 模式(关键前提)
将 FlatFileItemReader 的 strict 属性设为 false,使其跳过初始化阶段的资源存在性校验。注意:此设置必须在 build() 前通过 .strict(false) 显式声明:
@Bean
public FlatFileItemReader<MyClass> reader() {
BeanWrapperFieldSetMapper<MyClass> beanWrapperMapper = new BeanWrapperFieldSetMapper<>();
beanWrapperMapper.setTargetType(MyClass.class);
return new FlatFileItemReaderBuilder<MyClass>()
.name("MyClassReader")
.resource(new FileSystemResource(inputFolder + File.separator + "my-input-file.csv"))
.delimited()
.names("field1", "field2")
.fieldSetMapper(beanWrapperMapper)
.strict(false) // ? 必须添加!否则仍会校验资源存在性
.build();
}⚠️ 注意:strict(false) 仅避免初始化失败,不改变读取逻辑。当首次调用 read() 时,若文件仍不存在,reader 将返回 null(表示流结束),后续 read() 调用持续返回 null,因此整个 Step 的 readCount 将为 0。
2. 在 Job 执行后识别空读取并触发降级逻辑
利用 JobExecutionListener 监听 Job 完成事件,检查对应 Step 的 readCount。若为 0,说明输入文件为空或不存在,此时可执行自定义逻辑(如写入空结果、发送告警、生成默认输出等):
@Component
public class EmptyInputHandler implements JobExecutionListener {
@Override
public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
// 获取第一个 Step(按需调整索引或名称匹配)
StepExecution stepExecution = jobExecution.getStepExecutions().stream()
.filter(se -> "myProcessingStep".equals(se.getStepName())) // 推荐按 Step 名精确匹配
.findFirst()
.orElse(null);
if (stepExecution != null && stepExecution.getReadCount() == 0) {
// ✅ 文件缺失或为空:执行降级逻辑
writeDefaultOutput(); // 示例:写入含提示信息的空报告
log.warn("Input file missing or empty; generated default output.");
}
}
}
private void writeDefaultOutput() {
// 示例:使用 FlatFileItemWriter 写入默认行
try (PrintWriter writer = new PrintWriter(
new FileWriter("output/default-result.csv"))) {
writer.println("status,reason");
writer.println("SKIPPED,Input file not found");
} catch (IOException e) {
throw new RuntimeException("Failed to write default output", e);
}
}
}? 提示:注册该监听器时,需将其注入 Job 构建器:
@Bean public Job myJob(JobRepository jobRepository, JobCompletionNotificationListener listener) { return new JobBuilder("myJob", jobRepository) .start(myStep()) .listener(listener) // ← 注册监听器 .build(); }
? 总结与最佳实践
- strict(false) 是绕过初始化校验的必要开关,但不能替代业务逻辑判断;
- readCount == 0 是判断“无有效输入”的可靠指标(前提是 reader 未配置 saveState=false,否则计数可能不准确);
- 避免在 ItemProcessor 或 ItemWriter 中做空文件判断——它们在 readCount > 0 时才被调用;
- 生产环境建议结合日志、监控和告警(如 Prometheus + Alertmanager),对高频 readCount == 0 场景进行根因分析;
- 若需更细粒度控制(如区分“文件不存在” vs “文件存在但为空”),可在 reader() 方法中预先检查 FileSystemResource.exists() 并设置 Job 参数,供后续步骤决策。
通过以上方式,即可实现健壮、可控的“容错式批处理”,让 Spring Batch 在面对不稳定外部依赖时依然保持高可用性。










