我想知道如何在我的ItemWriter
中确定Spring Batch当前是处于分块处理模式还是回退的单个项处理模式。首先,我找不到有关这种回退机制的实现方式的信息。
即使我还没有找到解决我的实际问题的方法,我还是想与你分享我对这种回退机制的了解。
如果我漏掉了什么,请随意添加附加信息的答案;-)
我想知道如何在我的ItemWriter
中确定Spring Batch当前是处于分块处理模式还是回退的单个项处理模式。首先,我找不到有关这种回退机制的实现方式的信息。
即使我还没有找到解决我的实际问题的方法,我还是想与你分享我对这种回退机制的了解。
如果我漏掉了什么,请随意添加附加信息的答案;-)
write()
方法中,您可以看到调用了RetryTemplate
。它还获取了对RetryCallback
和RecoveryCallback
的两个引用。RetryTemplate
。找到以下方法:protected <T> T doExecute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState state)
您可以看到,RetryTemplate
会在未耗尽的情况下(即在我们的配置中仅一次)进行重试。这样的重试将由可重试异常引起。不可重试异常将立即中止重试机制。
在重试用完或被中止后,将调用 RecoveryCallback
:
e = handleRetryExhausted(recoveryCallback, context, state);
这就是单个项目处理模式的运作方式!
在处理器的write()
方法中定义的RecoveryCallback将锁定输入块(inputs.setBusy(true)
)并运行其scan()
方法。在这里,您可以看到从块中取出了一个单独的项目:
List<O> items = Collections.singletonList(outputIterator.next());
如果这个单独的项目能够被ItemWriter
正确处理,那么块将完成,并且ChunkOrientedTasklet
将运行另一个块(用于下一个单独的项目)。这将导致对RetryCallback
的常规调用,但由于块已被RecoveryTemplate
锁定,因此scan()
方法将立即被调用:
if (!inputs.isBusy()) {
// ...
}
else {
scan(contribution, inputs, outputs, chunkMonitor);
}
因此,另一个单独的项目将被处理并重复此过程,直到原始块逐个项目地被处理:
if (outputs.isEmpty()) {
inputs.setBusy(false);
就是这样,希望这篇内容对你有所帮助。我更希望你能通过搜索引擎轻松找到它,而不是浪费太多时间自己寻找。;-)
我原来的问题是ItemWriter想知道它是在块模式还是单个项模式下,可能的方法之一是以下几种替代方案之一:
当传递的块是java.util.Collections.SingletonList
时,我们会相当确定,因为FaultTolerantChunkProcessor
执行以下操作:
List items = Collections.singletonList(outputIterator.next());
不幸的是,这个类是私有的,所以我们无法使用instanceOf
进行检查。
相反,如果块是ArrayList
,我们也可以相当确定,因为Spring Batch的Chunk
类使用它:
private List items = new ArrayList();
无论如何,我仍然认为这种方法太模糊了。我更希望框架提供这些信息。
另一种选择是将我的ItemWriter
钩入框架执行中。也许ItemWriteListener.onWriteError()
是合适的。
更新:如果您处于单项目模式并在ItemWriter
中抛出异常,则不会调用onWriteError()
方法。我认为这是一个错误,我已经提出了https://jira.springsource.org/browse/BATCH-2027。
所以这个替代方案被排除了。
private int writeErrorCount = 0;
@Override
public void write(final List<? extends Long> items) throws Exception {
try {
writeWhatever(items);
} catch (final Exception e) {
if (this.writeErrorCount == 0) {
this.writeErrorCount = items.size();
} else {
this.writeErrorCount--;
}
throw e;
}
this.writeErrorCount--;
}
public boolean isWriterInSingleItemMode() {
return writeErrorCount != 0;
}