getCause()用于在SkipPolicy中递归追溯异常根本原因以精准跳过,如识别被包装的NumberFormatException;需配合skipLimit和skip()白名单使用,且仅限当前chunk生效。
在 spring batch 的跳过策略中,getcause() 主要用于获取导致跳过的异常原因,从而让跳过逻辑更精准——比如只跳过特定异常类型(如 numberformatexception),而对其他异常(如 nullpointerexception)仍抛出失败。关键不是直接调用 getcause(),而是通过 skippolicy 接口的 shouldskip(throwable, int) 方法,在其中检查异常链,用 getcause() 向上追溯根本原因。
理解 skip 时的异常来源
Spring Batch 在处理 item(读、处理、写)过程中发生异常时,会将原始异常包装为 SkipException 或直接传入 shouldSkip。实际传入的 Throwable 可能是:
- 业务代码抛出的原始异常(如
IllegalArgumentException) - 被 Spring Batch 包装后的异常(如
ItemProcessingException,其getCause()才是业务异常) - 嵌套多层的异常(例如
RuntimeException → DataAccessException → SQLException)
因此,不能只看 instanceof 当前异常类型,而要递归调用 getCause() 找到最内层或目标异常。
编写基于 getCause 的 SkipPolicy
实现 SkipPolicy 时,在 shouldSkip 中遍历异常链。推荐使用 Apache Commons Lang 的 ExceptionUtils.getRootCause(),或手动循环提取:
public class CustomSkipPolicy implements SkipPolicy {
@Override
public boolean shouldSkip(Throwable t, int skipCount) {
// 向上查找是否有 NumberFormatException(不管嵌套几层)
Throwable cause = t;
while (cause != null) {
if (cause instanceof NumberFormatException) {
return skipCount < 3; // 最多跳过 3 次
}
cause = cause.getCause();
}
return false; // 其他异常不跳过
}
}
注意:不要仅判断 t instanceof NumberFormatException,否则会漏掉被包装的情况(如 ItemProcessException 包裹了 NumberFormatException)。
立即学习“Java免费学习笔记(深入)”;
在 Step 中配置并生效
将自定义策略注册到 Step,确保它作用于对应阶段(如 processor 或 writer):
@Bean
public Step myStep() {
return stepBuilderFactory.get("myStep")
.<String, Integer>chunk(10)
.reader(itemReader())
.processor(itemProcessor()) // 异常可能在此处抛出
.writer(itemWriter())
.faultTolerant()
.skipPolicy(new CustomSkipPolicy()) // ← 注册策略
.skip(NumberFormatException.class) // 可选:声明“允许跳过”的类型(仅作文档/校验,不替代 shouldSkip 逻辑)
.build();
}
重要:skip(NumberFormatException.class) 是声明式白名单,Spring Batch 会先检查该类型是否在白名单中,再调用 shouldSkip。所以二者需一致,否则策略不会触发。
调试与验证技巧
跳过逻辑不易观察,建议:
- 在
shouldSkip中加日志,打印t.getClass().getName()和ExceptionUtils.getStackTrace(t) - 故意在 processor 中 throw new NumberFormatException() 测试是否跳过
- 用
@BeforeChunk和@AfterChunk监控 chunk 状态变化 - 检查 job execution 日志中是否出现
Skipping item和对应的异常摘要
不复杂但容易忽略:跳过只对当前 chunk 内的 item 生效,不影响后续 chunk;且跳过次数限制(skipLimit)必须显式设置,否则默认为 0(即不允许跳过)。


















