Spring Batch 跳过策略配置
Spring batch job执行过程中遇到任何错误,默认情况下将使得相应步骤执行失败。但有些场景我们希望跳过造成特定异常的当前处理项。本文探讨Spring batch 提供的两种方法配置跳过逻辑。
1.示例环境说明
为了简化说明,本文重用Spring Batch 入门教程 中的示例,实现把csv文件中的一些财务数据转换为xml格式。
但我们增加一些错误数据:
username, user_id, transaction_date, transaction_amount
devendra, 1234, 31/10/2015, 10000
john, 2134, 3/12/2015, 12321
robin, 2134, 2/02/2015, 23411
, 2536, 3/10/2019, 100
mike, 9876, 5/11/2018, -500
, 3425, 10/10/2017, 9999
最后三行有一些无效数据,其中第5、7行没有username字段,第6行金额值为负数。下面章节我们的目标就是配置让批处理程序跳过这些错误数据。
2. 跳过限制和该跳过异常的配置
2.1. 使用skip 和 skipLimit方法
下面先讨论第一中方法,使用skip 和 skipLimit方法实现执行失败时跳过处理项。
@Bean
public Step skippingStep(ItemProcessor<Transaction, Transaction> processor, ItemWriter<Transaction> writer) throws ParseException {
return stepBuilderFactory
.get("skippingStep")
.<Transaction, Transaction>chunk(10)
.reader(itemReader(invalidInputCsv))
.processor(processor)
.writer(writer)
.faultTolerant()
.skipLimit(2)
.skip(MissingUsernameException.class)
.skip(NegativeAmountException.class)
.build();
}
首先需要启用skip功能,需要在构建步骤时包括faultTolerant() 方法调用。在skip 和 skipLimit方法中,定义想跳过的异常类及最大跳过项数量。
上面示例中,如果在执行读、处理或写过程中无论遇到MissingUsernameException 或 NegativeAmountException 异常,当前正在处理的数据项被忽略并计数总数不超过2条。因此,第三次任何异常发生则整个执行失败。
2.2. 使用noSkip方法
在前面示例中,任何其他类型异常(除了 MissingUsernameException 和 NegativeAmountException)仍会导致执行失败。但有些场景指定异常发生执行步骤失败而跳过任何其他异常更合适。
下面看如何使用skip, skipLimit, noSkip方法进行配置:
@Bean
public Step skippingStep( ItemProcessor<Transaction, Transaction> processor, ItemWriter<Transaction> writer) throws ParseException {
return stepBuilderFactory
.get("skippingStep")
.<Transaction, Transaction>chunk(10)
.reader(itemReader(invalidInputCsv))
.processor(processor)
.writer(writer)
.faultTolerant()
.skipLimit(2)
.skip(Exception.class)
.noSkip(SAXException.class)
.build();
}
这里配置让 Spring Batch除了SAXException异常外跳过任何异常,则意味着SAXException 异常总会引发步骤执行失败。配置中skip() 和 noSkip() 顺序没有影响。
3. 使用自定义跳过策略
实际应用中可能需要更复杂的跳过检查机制,因此Spring Batch框架提供了SkipPolicy 接口。我们可以实现自己的跳过逻辑并插入至步骤定义中。
继续使用前面的示例,假如我们仍需定义最大跳过项为2,仅跳过MissingUsernameException 和 NegativeAmountException 两种异常。但再增加一个约束条件,仅当金额不超过一定限制时才能跳过NegativeAmountException异常。自定义的SkipPolicy实现如下:
public class CustomSkipPolicy implements SkipPolicy {
private static final int MAX_SKIP_COUNT = 2;
private static final int INVALID_TX_AMOUNT_LIMIT = -1000;
@Override
public boolean shouldSkip(Throwable throwable, int skipCount)
throws SkipLimitExceededException {
if (throwable instanceof MissingUsernameException && skipCount < MAX_SKIP_COUNT) {
return true;
}
if (throwable instanceof NegativeAmountException && skipCount < MAX_SKIP_COUNT ) {
NegativeAmountException ex = (NegativeAmountException) throwable;
if(ex.getAmount() < INVALID_TX_AMOUNT_LIMIT) {
return false;
} else {
return true;
}
}
return false;
}
}
现在我们能在定义步骤中使用自定义跳过策略:
@Bean
public Step skippingStep(
ItemProcessor<Transaction, Transaction> processor,
ItemWriter<Transaction> writer) throws ParseException {
return stepBuilderFactory
.get("skippingStep")
.<Transaction, Transaction>chunk(10)
.reader(itemReader(invalidInputCsv))
.processor(processor)
.writer(writer)
.faultTolerant()
.skipPolicy(new CustomSkipPolicy())
.build();
}
与前面配置类似,仍需要使用faultTolerant() 方法启用跳过功能。但这次没调用skip() 或 noSkip(),而是使用skipPolicy()方法并指定自定义的SkipPolicy 接口实现。
我们看到这种方法更加灵活,为实际应用中理想选择。
4. 总结
本文我们提供两种方法实现Spring Batch的容错处理功能。虽然使用skipLimit() 及 skip() 、noSkip()方法比较简单,但使用自定义的SkipPolicy实现更强大、灵活。