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
<p>注意:不要仅判断 <code>t instanceof NumberFormatException</code>,否则会漏掉被包装的情况(如 <code>ItemProcessException</code> 包裹了 <code>NumberFormatException</code>)。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7672" title="java-enterprise"><img
src="https://img.php.cn/upload/skill/000/000/081/179161929545163.jpg" alt="java-enterprise" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7672" title="java-enterprise" class="overflowclass">java-enterprise</a>
<p class="overflowclass">Java企业开发专家,专注于Spring Boot、微服务架构和JVM优化。适用于:Java语言掌握、</p>
</div>
<a rel="nofollow" href="/xiazai/skill7672" title="java-enterprise" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<h3>在 Step 中配置并生效</h3>
<p>将自定义策略注册到 <code>Step</code>,确保它作用于对应阶段(如 processor 或 writer):</p>
<pre class="brush:java;toolbar:false;">@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();
}</string>
重要: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(即不允许跳过)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










