1. 簡介
我們使用 Spring Batch 來構建由多個步驟組成的作業,這些步驟負責讀取、轉換和寫入數據。如果作業中的步驟有多個路徑,類似於我們在代碼中使用 if 語句,我們稱之為作業流程為 條件型。
在本教程中,我們將探討兩種創建具有條件流的 Spring Batch 作業的方法。
2. 退出狀態和批處理狀態
當我們在 Spring Batch 框架中指定一個條件步驟時,我們正在使用步驟或作業的退出狀態。因此,我們需要理解步驟和作業中的批處理狀態和退出狀態之間的區別:
- BatchStatus 是一個枚舉,代表步驟/作業的狀態,並由 Batch 框架內部使用
- 可能的取值包括:ABANDONED、COMPLETED、FAILED、STARTED、STARTING、STOPPED、STOPPING、UNKNOWN
- ExitStatus 是步驟執行完成後,執行狀態,用於條件確定流程
默認情況下,步驟或作業的 ExitStatus 與其 BatchStatus 相同。 還可以設置自定義的 ExitStatus 以驅動流程。
3. 條件流程
假設我們有一個物聯網設備向我們發送測量數據。這些測量數據是整數數組,我們需要在任何測量數據包含正整數時發送通知。
換句話説,我們需要在檢測到正數測量值時發送通知。
3.1. 退出狀態 (ExitStatus)</h3
重要的是,我們使用步驟的退出狀態來驅動條件流程。
要設置步驟的退出狀態,我們需要使用 StepExecution 對象的 setExitStatus 方法。為了做到這一點,我們需要創建一個擴展 ItemListenerSupport 的 ItemProcessor,並獲取步驟的 StepExecution。
我們使用它將步驟的退出狀態設置為 NOTIFY,當我們找到一個正數時。 當我們根據批處理作業中的數據確定退出狀態時,我們可以使用 ItemProcessor。
讓我們看看我們的 NumberInfoClassifier,以查看我們需要的方法:
public class NumberInfoClassifier extends ItemListenerSupport<NumberInfo, Integer>
implements ItemProcessor<NumberInfo, Integer> {
private StepExecution stepExecution;
@BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
this.stepExecution.setExitStatus(new ExitStatus(QUIET));
}
@Override
public Integer process(NumberInfo numberInfo) throws Exception {
return Integer.valueOf(numberInfo.getNumber());
}
@Override
public void afterProcess(NumberInfo item, Integer result) {
super.afterProcess(item, result);
if (item.isPositive()) {
stepExecution.setExitStatus(new ExitStatus(NOTIFY));
}
}
}注意:在本例中,我們使用 ItemProcessor 來設置 ExitStatus,但我們也可以在步驟的 ItemReader 或 ItemWriter 中輕鬆完成。
最後,當我們創建我們的 job 時,我們會告訴我們的 JobBuilder 以便為任何以 NOTIFY 狀態退出步驟發送通知。
new JobBuilder("Number generator - second dataset", jobRepository)
.start(dataProviderStep)
.on("NOTIFY").to(notificationStep)
.end()
.build();此外,當我們在工作流程中包含額外的條件分支和多個退出代碼時,可以使用 JobBuilder 的 from 和 on 方法將其添加到工作流程中。
new JobBuilder("Number generator - second dataset", jobRepository)
.start(dataProviderStep)
.on("NOTIFY").to(notificationStep)
.from(step).on("LOG_ERROR").to(errorLoggingStep)
.end()
.build();現在,每當我們的 ItemProcessor 看到一個正數時,它會指示我們的任務運行 notificationStep,該步驟只需將一條消息打印到 System.out:
Second Dataset Processor 11
Second Dataset Processor -2
Second Dataset Processor -3
[Number generator - second dataset] contains interesting data!!
如果數據集中沒有包含正數,我們就不再會看到 notificationStep 消息:
Second Dataset Processor -1
Second Dataset Processor -2
Second Dataset Processor -3
3.2. 使用JobExecutionDecider進行程序化分支
或者,我們可以使用實現JobExecutionDecider的類來確定任務流程。這在我們有外部因素來確定執行流程時尤其有用。
要使用此方法,我們首先需要修改我們的ItemProcessor,以移除ItemListenerSupport接口和@BeforeStep方法:
public class NumberInfoClassifierWithDecider extends ItemListenerSupport<NumberInfo, Integer>
implements ItemProcessor<NumberInfo, Integer> {
@Override
public Integer process(NumberInfo numberInfo) throws Exception {
return Integer.valueOf(numberInfo.getNumber());
}
}
接下來,我們創建一個 decider 類,該類確定我們的步驟的通知狀態:
public class NumberInfoDecider implements JobExecutionDecider {
private boolean shouldNotify() {
return true;
}
@Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
if (shouldNotify()) {
return new FlowExecutionStatus(NOTIFY);
} else {
return new FlowExecutionStatus(QUIET);
}
}
}
然後,我們設置我們的 Job 使用流程中的決策器:
new JobBuilder("Number generator - third dataset", jobRepository)
.start(dataProviderStep)
.next(new NumberInfoDecider()).on("NOTIFY").to(notificationStep)
.end()
.build();4. 結論
在本快速教程中,我們探討了兩種使用 Spring Batch 實現條件流程的方法。首先,我們研究瞭如何使用 ExitStatus 來控制我們的作業流程。
然後,我們研究瞭如何通過定義自己的 JobExecutionDecider 來程序化控制流程。