高階元資料使用
JobRegistry
JobRegistry 用於跟蹤上下文中哪些作業可用,並可由 JobOperator 操作。它也適用於在應用程式上下文中集中收集作業,即使它們是在其他地方(例如,在子上下文)建立的。您還可以使用自定義 JobRegistry 實現來操作已註冊作業的名稱和其他屬性。框架只提供了一個實現,該實現基於從作業名稱到作業例項的簡單對映,即 MapJobRegistry。
-
Java
-
XML
使用 @EnableBatchProcessing 時,會為您提供一個 MapJobRegistry。以下示例展示瞭如何配置您自己的 JobRegistry
...
@Bean
public JobRegistry jobRegistry() throws Exception {
return new MyCustomJobRegistry();
}
...
以下示例展示瞭如何為 XML 中定義的作業包含 JobRegistry
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
Spring Batch 提供的 MapJobRegistry 足夠智慧,可以自動填充應用程式上下文中所有作業。但是,如果您使用 JobRegistry 的自定義實現,則需要手動填充要透過作業操作器操作的作業。
JobParametersIncrementer
JobOperator 中的大多數方法都一目瞭然,您可以在介面的 Javadoc 中找到更詳細的解釋。但是,startNextInstance 方法值得注意。此方法始終啟動 Job 的新例項。如果 JobExecution 中存在嚴重問題並且需要從頭開始重新啟動 Job,這會非常有用。與 JobLauncher(它需要一個觸發新 JobInstance 的新 JobParameters 物件)不同,如果引數與任何以前的引數集不同,startNextInstance 方法使用繫結到 Job 的 JobParametersIncrementer 來強制 Job 到一個新的例項
public interface JobParametersIncrementer {
JobParameters getNext(JobParameters parameters);
}
JobParametersIncrementer 的契約是,給定一個 JobParameters 物件,它透過遞增其中可能包含的任何必要值來返回“下一個”JobParameters 物件。此策略很有用,因為框架無法知道對 JobParameters 的哪些更改使其成為“下一個”例項。例如,如果 JobParameters 中唯一的值是日期,並且應該建立下一個例項,那麼該值應該增加一天還是一週(例如,如果作業是每週執行的)?同樣,對於任何有助於識別 Job 的數值也可以這樣說,如下例所示
public class SampleIncrementer implements JobParametersIncrementer {
public JobParameters getNext(JobParameters parameters) {
if (parameters==null || parameters.isEmpty()) {
return new JobParametersBuilder().addLong("run.id", 1L).toJobParameters();
}
long id = parameters.getLong("run.id",1L) + 1;
return new JobParametersBuilder().addLong("run.id", id).toJobParameters();
}
}
在此示例中,鍵為 run.id 的值用於區分 JobInstances。如果傳入的 JobParameters 為 null,則可以假定該 Job 從未執行過,因此可以返回其初始狀態。但是,如果不是,則獲取舊值,將其遞增 1,然後返回。
-
Java
-
XML
對於用 Java 定義的作業,您可以透過構建器中提供的 incrementer 方法將增量器與 Job 相關聯,如下所示
@Bean
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.incrementer(sampleIncrementer())
...
.build();
}
對於在 XML 中定義的作業,您可以透過名稱空間中的 incrementer 屬性將增量器與 Job 相關聯,如下所示
<job id="footballJob" incrementer="sampleIncrementer">
...
</job>
停止作業
JobOperator 最常見的用例之一是優雅地停止作業
Set<Long> executions = jobOperator.getRunningExecutions("sampleJob");
jobOperator.stop(executions.iterator().next());
關閉不是立即的,因為無法強制立即關閉,特別是如果執行當前在開發人員程式碼中,而框架無法控制這些程式碼,例如業務服務。但是,一旦控制權返回給框架,它會將當前 StepExecution 的狀態設定為 BatchStatus.STOPPED,儲存它,並在完成之前對 JobExecution 執行相同的操作。
處理外部中斷訊號
從 v6.0+ 開始,Spring Batch 提供了一個 JobExecutionShutdownHook,您可以將其附加到 JVM 執行時,以攔截外部中斷訊號並優雅地停止作業執行
Thread springBatchHook = new JobExecutionShutdownHook(jobExecution, jobOperator);
Runtime.getRuntime().addShutdownHook(springBatchHook);
JobExecutionShutdownHook 需要跟蹤作業執行,以及對將用於停止執行的作業操作器的引用。
恢復作業
如果未正確執行優雅關閉(即 JVM 突然關閉),Spring Batch 將無法正確更新執行狀態以重新啟動失敗的作業執行。在這種情況下,作業執行將保持在 STARTED 狀態,該狀態不可重新啟動。在這種情況下,可以使用 JobOperator API 恢復此類作業執行
JobExecution jobExecution = ...; // get the job execution to recover
jobOperator.recover(jobExecution);
jobOperator.restart(jobExecution);
中止作業
狀態為 FAILED 的作業執行可以重新啟動(如果 Job 可重新啟動)。狀態為 ABANDONED 的作業執行不能由框架重新啟動。ABANDONED 狀態也用於步驟執行中,以將其標記為在重新啟動的作業執行中可跳過。如果作業正在執行並遇到在之前失敗的作業執行中標記為 ABANDONED 的步驟,它將繼續執行下一個步驟(由作業流定義和步驟執行退出狀態確定)。
如果程序死亡(kill -9 或伺服器故障),作業當然沒有執行,但 JobRepository 無法知道,因為在程序死亡之前沒有人告訴它。您必須手動告知它,您知道執行要麼失敗,要麼應該被視為中止(將其狀態更改為 FAILED 或 ABANDONED)。這是一個業務決策,無法自動化。僅當可重新啟動且您知道重新啟動資料有效時,才將狀態更改為 FAILED。