Spring Batch FlatFileItemReader遇错误令牌数如何继续执行?
当然可以搞定这个问题!Spring Batch其实已经内置了成熟的机制来处理坏行场景,根本不用你自己去扩展FlatFileItemReader,下面给你几个最实用的最佳方案:
方案一:利用Spring Batch的Skip容错机制(官方推荐)
这是处理此类问题最优雅的方式,Spring Batch的faultTolerant()配置专门用来处理读取/处理/写入过程中的异常,你只需要指定要跳过的异常类型和最大跳过次数即可,遇到符合条件的坏行时,框架会自动跳过并继续执行,直到达到跳过上限才会终止任务。
配置示例
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.SkipListener; import org.springframework.batch.core.step.builder.StepBuilderFactory; import org.springframework.batch.item.file.FlatFileParseException; import org.springframework.context.annotation.Bean; @Bean public Step csvProcessingStep(ItemReader<MyRecord> reader, ItemProcessor<MyRecord, MyRecord> processor, ItemWriter<MyRecord> writer, StepBuilderFactory stepBuilderFactory) { Logger log = LoggerFactory.getLogger(this.getClass()); return stepBuilderFactory.get("csvProcessingStep") .<MyRecord, MyRecord>chunk(10) // 按10条数据为一个批次处理 .reader(reader) .processor(processor) .writer(writer) .faultTolerant() // 开启容错模式 .skip(FlatFileParseException.class) // 指定要跳过的解析异常 .skipLimit(100) // 最多允许跳过100条坏行,可根据业务调整 .listener(new SkipListener<MyRecord, MyRecord>() { @Override public void onSkipInRead(Throwable t) { // 记录坏行的详细信息,方便后续排查 if (t instanceof FlatFileParseException) { FlatFileParseException parseException = (FlatFileParseException) t; log.error("跳过解析失败的行,行号:{},原始内容:{}", parseException.getLineNumber(), parseException.getInput()); } } }) .build(); }
方案优势
- 无需修改原有
FlatFileItemReader的实现,完全利用框架原生能力 - 可以精准控制允许跳过的异常类型和数量,避免无限制跳过
- 通过
SkipListener可以轻松记录坏行信息,便于后续分析问题
方案二:自定义包装ItemReader(定制化场景)
如果你的业务需要更细粒度的跳过逻辑(比如根据坏行内容决定是否跳过),可以自己写一个包装类,把FlatFileItemReader作为委托类,手动捕获异常并处理。
实现示例
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.NonTransientResourceException; import org.springframework.batch.item.ParseException; import org.springframework.batch.item.UnexpectedInputException; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.FlatFileParseException; public class SkipBadLineItemReader<T> implements ItemReader<T> { private static final Logger log = LoggerFactory.getLogger(SkipBadLineItemReader.class); private final FlatFileItemReader<T> delegateReader; private final int maxSkipCount; private int currentSkipCount = 0; public SkipBadLineItemReader(FlatFileItemReader<T> delegateReader, int maxSkipCount) { this.delegateReader = delegateReader; this.maxSkipCount = maxSkipCount; } @Override public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { try { return delegateReader.read(); } catch (FlatFileParseException e) { if (currentSkipCount >= maxSkipCount) { // 超过跳过上限,抛出异常终止任务 throw new IllegalStateException("跳过的坏行数量已超过上限:" + maxSkipCount, e); } currentSkipCount++; log.error("跳过坏行,行号:{},内容:{}", e.getLineNumber(), e.getInput()); // 递归调用read方法,获取下一条有效数据 return read(); } } }
使用方式
在配置FlatFileItemReader的地方,用这个包装类包裹起来:
@Bean public ItemReader<MyRecord> skipBadLineReader() { FlatFileItemReader<MyRecord> originalReader = new FlatFileItemReader<>(); // 配置originalReader的资源、行映射器等... return new SkipBadLineItemReader<>(originalReader, 100); }
注意事项
- 这种方式需要自己管理跳过计数,不如框架的Skip机制集成度高
- Spring Batch的任务统计(比如跳过行数)可能不会统计到手动跳过的行,需要自己额外记录
总结
优先推荐使用方案一的Skip容错机制,这是Spring Batch官方设计的容错方案,配置简单、功能完善,能满足绝大多数场景的需求。只有当你需要非常定制化的跳过逻辑(比如根据坏行内容做特殊判断)时,再考虑方案二的自定义包装方式。
内容的提问来源于stack exchange,提问作者DavidR
相关产品推荐
相关产品推荐

