如何正确处理Spring Batch Step Writer异常以跳过错误元素继续执行
问题1解答
你当前的代码逻辑里已经对三类异常做了显式捕获,且捕获后没有向上抛出异常,所以触发异常时只会跳过当前出错的单个元素,不会导致整个Job失败。但这种处理方式存在两个明显缺陷:
- Spring Batch框架本身感知不到该条记录处理失败,你无法通过框架自带的跳过统计、失败记录监听等能力做后续的错误溯源、重跑处理
- 仅打印异常栈的容错方式无法有效留存错误上下文,后续排查问题时无法定位具体是哪条记录、因为什么原因处理失败
问题2解答
你当前的写法本身不会导致Job失败,但更推荐使用Spring Batch原生的跳过机制实现容错,既能实现单条错误记录跳过的需求,又能利用框架的能力做错误管理,改造步骤如下:
- 首先修改你的
NotaryWriter代码,去掉手动捕获异常的逻辑,直接把异常向上抛出:
@Component public class NotaryWriter implements ItemWriter<NotaryDetails> { @Autowired private WpService wpService; public NotaryWriter(WpService wpService) { super(); this.wpService = wpService; } @Override public void write(List<? extends NotaryDetails> items) throws Exception { items.stream().forEach(currentNotary -> { System.out.println("NotaryWriter - WRITING OUTPUT: " + currentNotary.toString()); int newNotaryPostId = this.wpService.insertOrUpdateNotaryAsWpPost(currentNotary); }); } }
- 在Step配置中添加跳过规则,指定需要跳过的异常类型、最大跳过次数,同时可以配置
SkipListener来留存失败记录的上下文:
@Bean public Step notaryProcessStep(StepBuilderFactory stepBuilderFactory, ItemReader<NotaryDetails> notaryReader, NotaryWriter notaryWriter, SkipListener<NotaryDetails, NotaryDetails> skipListener) { return stepBuilderFactory.get("notaryProcessStep") .<NotaryDetails, NotaryDetails>chunk(10) // 按你实际的chunk大小配置 .reader(notaryReader) .writer(notaryWriter) // 配置跳过规则 .skip(JsonProcessingException.class) .skip(UnsupportedEncodingException.class) .skip(URISyntaxException.class) // 配置最大跳过次数,超过后Job才会失败 .skipLimit(100) // 可选:配置跳过监听器,记录失败的记录信息 .listener(skipListener) .build(); }
- (可选)自定义
SkipListener实现,记录失败的记录详情到日志或者错误表中,方便后续排查:
@Component public class NotarySkipListener implements SkipListener<NotaryDetails, NotaryDetails> { private static final Logger LOGGER = LoggerFactory.getLogger(NotarySkipListener.class); @Override public void onSkipInRead(Throwable t) { // 读阶段跳过的逻辑 } @Override public void onSkipInWrite(NotaryDetails item, Throwable t) { LOGGER.error("处理公证人记录失败,记录内容:{},错误原因:{}", item.toString(), t.getMessage(), t); // 也可以写入错误表,后续做重跑 } @Override public void onSkipInProcess(NotaryDetails item, Throwable t) { // 处理阶段跳过的逻辑 } }
这种原生实现的优势在于:
- 框架自动完成错误记录的跳过,不需要你手动在业务代码里做异常捕获,代码更简洁
- 可以通过Spring Batch的执行上下文直接查询跳过的记录数,不需要自己做统计
- 可以统一管理所有错误记录的处理逻辑,避免散落在各个业务组件中
内容的提问来源于stack exchange,提问作者AndreaNobili
相关产品推荐
相关产品推荐

