執行 Job
至少,啟動批次 job 需要兩件事:要啟動的 Job
和 JobLauncher
。兩者可以包含在相同的 context 或不同的 context 中。例如,如果您從命令列啟動 job,則每個 Job
都會實例化一個新的 JVM。因此,每個 job 都有自己的 JobLauncher
。但是,如果您從 Web 容器內在 HttpRequest
的範圍內執行,則通常有一個 JobLauncher
(配置為非同步 job 啟動),多個請求會調用它來啟動其 job。
從命令列執行 Job
如果您想從企業排程器執行您的 job,命令列是主要介面。這是因為大多數排程器(除了 Quartz,除非使用 NativeJob
)直接與作業系統程序一起工作,主要由 shell 腳本啟動。除了 shell 腳本外,還有許多方法可以啟動 Java 程序,例如 Perl、Ruby 甚至建置工具,例如 Ant 或 Maven。但是,由於大多數人熟悉 shell 腳本,因此此範例著重於它們。
CommandLineJobRunner
由於啟動 job 的腳本必須啟動 Java 虛擬機器,因此需要一個具有 main
方法的類別作為主要進入點。Spring Batch 提供了一個實現來實現此目的:CommandLineJobRunner
。請注意,這只是一種引導應用程式的方式。啟動 Java 程序的方法有很多種,這個類別絕不應被視為最終的。CommandLineJobRunner
執行四項任務
-
載入適當的
ApplicationContext
。 -
將命令列引數解析為
JobParameters
。 -
根據引數定位適當的 job。
-
使用應用程式 context 中提供的
JobLauncher
來啟動 job。
所有這些任務僅使用傳入的引數即可完成。下表描述了必要的引數
|
用於建立 |
|
要執行的 job 名稱。 |
這些引數必須傳入,路徑在前,名稱在後。之後的所有引數都視為 job 參數,並轉換為 JobParameters
物件,並且必須採用 name=value
的格式。
-
Java
-
XML
以下範例顯示了作為 job 參數傳遞給以 Java 定義的 job 的日期
<bash$ java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date=2007-05-05,java.time.LocalDate
以下範例顯示了作為 job 參數傳遞給以 XML 定義的 job 的日期
<bash$ java CommandLineJobRunner endOfDayJob.xml endOfDay schedule.date=2007-05-05,java.time.LocalDate
預設情況下, 在以下範例中,
您可以透過使用自訂 |
-
Java
-
XML
在大多數情況下,您會希望使用 manifest 在 jar 中宣告您的 main
類別。但是,為了簡單起見,直接使用了該類別。此範例使用來自 批次領域語言 的 EndOfDay
範例。第一個引數是 io.spring.EndOfDayJobConfiguration
,它是包含 Job 的配置類別的完整類別名稱。第二個引數 endOfDay
代表 job 名稱。最後一個引數 schedule.date=2007-05-05,java.time.LocalDate
會轉換為 java.time.LocalDate
類型的 JobParameter
物件。
以下範例顯示了 Java 中 endOfDay
的範例配置
@Configuration
@EnableBatchProcessing
public class EndOfDayJobConfiguration {
@Bean
public Job endOfDay(JobRepository jobRepository, Step step1) {
return new JobBuilder("endOfDay", jobRepository)
.start(step1)
.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet((contribution, chunkContext) -> null, transactionManager)
.build();
}
}
在大多數情況下,您會希望使用 manifest 在 jar 中宣告您的 main
類別。但是,為了簡單起見,直接使用了該類別。此範例使用來自 批次領域語言 的 EndOfDay
範例。第一個引數是 endOfDayJob.xml
,它是包含 Job
的 Spring ApplicationContext。第二個引數 endOfDay,
代表 job 名稱。最後一個引數 schedule.date=2007-05-05,java.time.LocalDate
會轉換為 java.time.LocalDate
類型的 JobParameter
物件。
以下範例顯示了 XML 中 endOfDay
的範例配置
<job id="endOfDay">
<step id="step1" parent="simpleStep" />
</job>
<!-- Launcher details removed for clarity -->
<beans:bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher" />
前面的範例過於簡單,因為在 Spring Batch 中執行批次 job 通常有更多要求,但它旨在展示 CommandLineJobRunner
的兩個主要要求:Job
和 JobLauncher
。
結束代碼
從命令列啟動批次 job 時,通常會使用企業排程器。大多數排程器都相當簡單,僅在程序層級工作。這表示它們只知道某些作業系統程序(例如它們調用的 shell 腳本)。在這種情況下,向排程器回報 job 的成功或失敗的唯一方法是透過傳回碼。傳回碼是程序傳回給排程器的數字,用於指示執行的結果。在最簡單的情況下,0 代表成功,1 代表失敗。但是,可能會有更複雜的情況,例如「如果 job A 傳回 4,則啟動 job B,如果 job B 傳回 5,則啟動 job C。」這種行為是在排程器層級配置的,但重要的是,諸如 Spring Batch 之類的處理框架提供了一種方法來傳回特定批次 job 的結束代碼的數字表示形式。在 Spring Batch 中,這封裝在 ExitStatus
中,在第 5 章中將更詳細地介紹。對於討論結束代碼的目的而言,唯一重要的是要知道 ExitStatus
具有一個結束代碼屬性,該屬性由框架(或開發人員)設定,並作為從 JobLauncher
傳回的 JobExecution
的一部分傳回。CommandLineJobRunner
透過使用 ExitCodeMapper
介面將此字串值轉換為數字
public interface ExitCodeMapper {
public int intValue(String exitCode);
}
ExitCodeMapper
的基本合約是,給定一個字串結束代碼,將傳回一個數字表示形式。job 執行器使用的預設實作是 SimpleJvmExitCodeMapper
,它針對完成傳回 0,針對一般錯誤傳回 1,針對任何 job 執行器錯誤(例如無法在提供的 context 中找到 Job
)傳回 2。如果需要比上述三個值更複雜的值,則必須提供 ExitCodeMapper
介面的自訂實作。由於 CommandLineJobRunner
是建立 ApplicationContext
的類別,因此無法「接線在一起」,因此任何需要覆寫的值都必須自動裝配。這表示如果在 BeanFactory
中找到 ExitCodeMapper
的實作,則會在建立 context 後將其注入到執行器中。提供您自己的 ExitCodeMapper
所需做的就是將實作宣告為根層級 bean,並確保它是執行器載入的 ApplicationContext
的一部分。
從 Web 容器內執行 Job
從歷史上看,離線處理(例如批次 job)是從命令列啟動的,如前所述。但是,在許多情況下,從 HttpRequest
啟動是一個更好的選擇。許多此類用例包括報告、臨時 job 執行和 Web 應用程式支援。由於批次 job(根據定義)是長時間執行的,因此最重要的考量是以非同步方式啟動 job

在這種情況下,控制器是一個 Spring MVC 控制器。有關 Spring MVC 的更多資訊,請參閱 Spring Framework 參考指南。控制器透過使用已配置為非同步啟動的 JobLauncher
來啟動 Job
,這會立即傳回 JobExecution
。Job
可能仍在執行中。但是,這種非阻塞行為讓控制器立即傳回,這是處理 HttpRequest
時所必需的。以下清單顯示了一個範例
@Controller
public class JobLauncherController {
@Autowired
JobLauncher jobLauncher;
@Autowired
Job job;
@RequestMapping("/jobLauncher.html")
public void handle() throws Exception{
jobLauncher.run(job, new JobParameters());
}
}