配置Spring Batch 跳过逻辑
Spring Batch处理过程中遇到错误将导致失败。但有些场景我们更希望能够跳过当前处理记录产生的异常。本文介绍如何配置跳过逻辑以及定义跳过策略。
1. 应用示例
为了说明我们搭建一个示例,转换一些财务数据从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行交易金额为负数。下面我们实现批处理功能,跳过这些不正确的记录。
1. 配置跳过限制和跳过异常
1.1 设置跳过限制
现在讨论配置job遇到什么异常跳过,及跳过和跳过限制方法:
@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();
}
首先启用跳过功能,通过再构建步骤阶段调用faultTolerant() 。在skip() 和 skipLimit() 方法中定义跳过异常和跳过最大记录数量。在上面示例中如果在读、处理或写过程中抛出 MissingUsernameException 或 NegativeAmountException 异常,那么当前处理记录将被忽略并记录次数(不能超过2条)。因此如果第三次任何抛出任何异常则整个步骤将失败。
1.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跳过任何Exception(在限制之内),除了SAXException,则意味着SAXException异常总是导致处理失败。skip() 和 noSkip() 方法的调用顺序没有影响。
2. 使用自定义SkipPolicy
有时需要更复杂跳过检查机制,Spring Batch提供了SkipPolicy接口。我们可以提供自己跳过逻辑实现并配置在步骤定义中。还是上面的示例,假设还是限制跳过两条记录,但除了MissingUsernameException 和 NegativeAmountException异常。但另外的约束如果NegativeAmountException异常中数量不超过特定限制可以跳过异常。下面实现自定义策略:
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, skipLimit 和 noSkip,而是使用skipPolicy() 方法配置自定义跳过策略。这种方法更加灵活,在实际应用中是最佳选择。
3. 总结
本文我们讨论Spring Batch的容错机制,跳过策略。通过示例展示如何配置跳过异常和限制次数,也介绍了自定义跳过策略实现更复杂、灵活的应用场景。