spring batch教程 之 配置並運行Job

Spring batch整體的架構設計使用如下關係圖來進行表示:



雖然Job對象看上去像是對於多個Step的一個簡單容器,但是開發者必須要注意許多配置項。此外,Job的運行以及Job運行過程中元數據如何被保存也是需要考慮的。本章將會介紹Job在運行時所需要注意的各種配置項。


1.1 Configuring a Job


Job接口 的實現有多個,但是在配置上命名空間存在着不同。必須依賴的只有三項:名稱 name,JobRespository 和 Step的列表:


<job id="footballJob">
   <step id="playerload" parent="s1" next="gameLoad"/>
   <step id="gameLoad" parent="s2" next="playerSummarization"/>
   <step id="playerSummarization" parent="s3"/>
</job>

在這個例子中使用了父類的bean定義來創建step,更多描述step配置的信息可以參考step configuration這一節。XML命名空間默認會使用id爲'jobRepository'的引用來作爲repository的定義。然而可以向如下顯式的覆蓋:


<job id="footballJob" job-repository="specialRepository">
   <step id="playerload" parent="s1" next="gameLoad"/>
   <step id="gameLoad" parent="s3" next="playerSummarization"/>
   <step id="playerSummarization" parent="s3"/>
</job>


此外,job配置的step還包含其他的元素,有併發處理(),顯示的流程控制()和外化的流程定義()。


1.1.1 Restartablity


執行批處理任務的一個關鍵問題是要考慮job被重啓後的行爲。如果一個 JobExecution 已經存在一個特定的 JobInstance,那麼這個job啓動時可以認爲是“重啓”。 理想情況下,所有任務都能夠在他們中止的地方啓動,但是有許多場景這是不可能的。在這種場景中就要有開發者來決定創建一個新的 JobInstance ,Spring對此也提供了一些幫助。如果job不需要重啓,而是總是作爲新的 JobInstance 來運行,那麼可重啓屬性可以設置爲'false':


<job id="footballJob" restartable="false">
...
</job>


設置重啓屬性restartable爲‘false’表示‘這個job不支持再次啓動’,重啓一個不可重啓的job會拋出JobRestartExceptio的異常:


   Job job = new SimpleJob();
   job.setRestartable(false);
   JobParameters jobParameters = new JobParameters();
   JobExecution firstExecution = jobRepository.createJobExecution(job, jobParameters);
   jobRepository.saveOrUpdate(firstExecution);
   try {
       jobRepository.createJobExecution(job, jobParameters);
       fail();
    } catch (JobRestartException e) {
//預計拋出JobRestartException異常
    }


這個JUnit代碼展示了創建一個不可重啓的Job後,第一次能夠創建 JobExecution ,第二次再創建相同的JobExcution會拋出一個 JobRestartException。


1.1.2 Intercepting Job Execution

在job執行過程中,自定義代碼能夠在生命週期中通過事件通知執行會是很有用的。SimpleJob能夠在適當的時機調用JobListener:


public interface JobExecutionListener {
  void beforeJob(JobExecution jobExecution);
  void afterJob(JobExecution jobExecution);
}


JobListener能夠添加到SimpleJob中去,作爲job的listener元素:


<job id="footballJob">
   <step id="playerload" parent="s1" next="gameLoad"/>
   <step id="gameLoad" parent="s2" next="playerSummarization"/>
   <step id="playerSummarization" parent="s3"/>
   <listeners>
      <listener ref="sampleListener"/>
   </listeners>
</job>


無論job執行成功或是失敗都會調用afterJob,都可以從 JobExecution 中獲取運行結果後,根據結果來進行不同的處理:


public void afterJob(JobExecution jobExecution){
    if( jobExecution.getStatus() == BatchStatus.COMPLETED ){
       //job執行成功 }
    else if(jobExecution.getStatus() == BatchStatus.FAILED){
       //job執行失敗 }
}


對應於這個interface的annotation爲:

  • @BeforeJob
  • @AfterJob

1.1.3 Inheriting from a parent Job


如果一組job配置共有相似,但又不是完全相同,那麼可以定義一個"父”job,讓這些job去繼承屬性。同Java的類繼承一樣,子job會把父job的屬性和元素合並進來。
下面的例子中,“baseJob”是一個抽象的job定義,只定義了一個監聽器列表。名爲“job1”的job是一個具體定義,它繼承了“baseJob"的監聽器,並且與自己的監聽器合併,最終生成的job帶有兩個監聽器,以及一個名爲”step1“的step。

<job id="baseJob" abstract="true">
   <listeners>
     <listener ref="listenerOne"/>
   </listeners>
</job>
<job id="job1" parent="baseJob">
   <step id="step1" parent="standaloneStep"/>
   <listeners merge="true">
     <listener ref="listenerTwo"/>
   </listeners>
</job>

1.1.4 JobParametersValidator


一個在xml命名空間描述的job或是使用任何抽象job子類的job,可以選擇爲運行時爲job參數定義一個驗證器。在job啓動時需要保證所有必填參數都存在的場景下,這個功能是很有用的。有一個DefaultJobParametersValidator可以用來限制一些簡單的必選和可選參數組合,你也可以實現接口用來處理更復雜的限制。驗證器的配置支持使用xml命名空間來作爲job的子元素,例如:

<job id="job1" parent="baseJob3">
   <step id="step1" parent="standaloneStep"/>
   <validator ref="paremetersValidator"/>
</job>

驗證器可以作爲一個引用(如上)來定義也可以直接內嵌定義在bean的命名空間中。


1.2 Java Config


在Spring 3版本中可以採用java程序來配置應用程序,來替代XML配置的方式。 正如在Spring Batch 2.2.0版本中,批處理任務中可以使用相同的java配置項來對其進行配置。關於Java的基礎配置的兩個組成部分分別是: @EnableBatchConfiguration註釋和兩個builder。

在Spring的體系中 @EnableBatchProcessing 註釋的工作原理與其它的帶有 @Enable * 的註釋類似。在這種情況
下, @EnableBatchProcessing 提供了構建批處理任務的基本配置。在這個基本的配置中,除了創建了一個 StepScope 的實例,還可以將一系列可用的bean進行自動裝配:

  • JobRepository bean 名稱 "jobRepository"
  • JobLauncher bean名稱"jobLauncher"
  • JobRegistry bean名稱"jobRegistry"
  • PlatformTransactionManager bean名稱 "transactionManager"
  • JobBuilderFactory bean名稱"jobBuilders"
  • StepBuilderFactory bean名稱"stepBuilders"

這種配置的核心接口是 BatchConfigurer。它爲以上所述的bean提供了默認的實現方式,並要求在context中提供一個bean,即 DataSource 。數據庫連接池由被 JobRepository 使用。

注意 只有一個配置類需要有@ enablebatchprocessing註釋。只要有一個類添加了這個註釋,則以上所有的bean都是可以使用的。

在基本配置中,用戶可以使用所提供的builder factory來配置一個job。下面的例子是通過 JobBuilderFactory 和
StepBuilderFactory 配置的兩個step job 。

@Configuration
@EnableBatchProcessing
@Import(DataSourceCnfiguration.class)
public class AppConfig {
   @Autowired
   private JobBuilderFactory jobs;
   @Autowired
   private StepBuilderFactory steps;
   @Bean
   public Job job() {
       return jobs.get("myJob").start(step1()).next(step2()).build();
   }
   @Bean
   protected Step step1(ItemReader<Person> reader, ItemProcessor<Person, Person> processor, ItemWriter<Person> writer) {
         return steps.get("step1")
           .<Person, Person> chunk(10)
           .reader(reader)
           .processor(processor)
           .writer(writer)
           .build();
      }
   @Bean
   protected Step step2(Tasklet tasklet) {
        return steps.get("step2")
           .tasklet(tasklet)
           .build();
      }
}

1.3 Configuring a JobRepository


之前說過,JobRepository 是基本的CRUD操作,用於持久化Spring Batch的領域對象(如JobExecution,StepExecution)。許多主要的框架組件(如JobLauncher,Job,Step)都需要使用JobRepository。batch的命名空間中已經抽象走許多JobRepository的實現細節,但是仍然需要一些配置:

<job-repository id="jobRepository"
    data-source="dataSource"
    transaction-manager="transactionManager"
    isolation-level-for-create="SERIALIZABLE"
    table-prefix="BATCH_"
    max-varchar-length="1000"/>

上面列出的配置除了id外都是可選的。如果沒有進行參數配置,默認值就是上面展示的內容,之所以寫出來是用於展示給讀者。 max-varchar-length 的默認值是2500,這表示varchar列的長度,在 sample schema scripts 中用於存儲類似於 exit code 這些描述的字符。如果你不修改schema並且也不會使用多字節編碼,那麼就不用修改它。

1.3.1 JobRepository 的事物配置


如果使用了namespace,repository會被自動加上事務控制,這是爲了確保批處理操作元數據以及失敗後重啓的狀態能夠被準確的持久化,如果repository的方法不是事務控制的,那麼框架的行爲就不能夠被準確的定義。 create* 方法的隔離級別會被單獨指定,爲了確保任務啓動時,如果兩個操作嘗試在同時啓動相同的任務,那麼只有一個任務能夠被成功啓動。這種方法默認的隔離級別是 SERIALIZABLE ,這是相當激進的做法: READ_COMMITED 能達到同樣效果;如果兩個操作不以這種方式衝突的話 READ_UNCOMMITED 也能很好工作。但是,由於調用 create* 方法是相當短暫的,只要數據庫支持,就不會對性能產生太大影響。它也能被這樣覆蓋:

<job-repository id="jobRepository" isolation-level-for-create="REPEATABLE_READ" />

如果factory的namespace沒有被使用,那麼可以使用AOP來配置repository的事務行爲:

<aop:config>
  <aop:advisor pointcut="execution(* org.springframework.batch.core..*Repository+.*(..))"/>
  <advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
     <tx:method name="*" />
  </tx:attributes>
</tx:advice>

這個配置片段基本上可以不做修改直接使用。記住加上適當的namespace描述去確保spring-tx和spring-aop(或是整個spring)都在classpath中。


1.3.2 修改 Table 前綴


JobRepository 可以修改的另一個屬性是元數據表的表前綴。默認是以BATCH_開頭, BATCH_JOB_EXECUTION 和
BATCH_STEP_EXECUTION 就是兩個例子。但是,有一些潛在的原因可能需要修改這個前綴。例如schema的名字需要被預置到表名中,或是不止一組的元數據表需要放在同一個schema中,那麼表前綴就需要改變:

<job-repository id="jobRepository" table-prefix="SYSTEM.TEST_" />

按照上面的修改配置,每一個元數據查詢都會帶上 SYSTEM.TEST_ 的前綴, BATCH_JOB_EXECUTION 將會被更換爲 SYSTEM.TEST_JOB_EXECUTION 。

注意:表名前綴是可配置的,表名和列名是不可配置的。

1.3.3 In-Memory Repository


有的時候不想把你的領域對象持久化到數據庫中,可能是爲了運行的更快速,因爲每次提交都要開銷額外的時間;也可能並不需要爲特定任務保存狀態。那麼Spring Batch還提供了內存Map版本的job倉庫:

<bean id="jobRepository"
   class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
   <property name="transactionManager" ref="transactionManager"/>
</bean>

需要注意的是 內存 Repository 是輕量的並且不能在兩個JVM實例間重啓任務,也不能允許同時啓動帶有相同參數的任務,不適合在多線程的任務或是一個本地分片任務的場景下使用。而使用數據庫版本的Repository則能夠擁有這些特性。

但是也需要定義一個事務管理器,因爲倉庫需要回滾語義,也因爲商業邏輯要求事務性(例如RDBMS訪問)。經過測試許多人覺得 ResourcelessTransactionManager 是很有用的。


1.3.4 Non-standard Database Types in a Repository


如果使用的數據庫平臺不在支持的平臺列表中,在SQL類型類似的情況下你可以使用近似的數據庫類型。使用原生的JobRepositoryFactoryBean 來取代命名空間縮寫後設置一個相似的數據庫類型:

<bean id="jobRepository" class="org...JobRepositoryFactoryBean">
    <property name="databaseType" value="db2"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

(如果沒有指定 databaseType ,JobRepositoryFactoryBean 會通過DataSource自動檢測數據庫的類型).平臺之間的主要不同之處在於主鍵的計算策略,也可能需要覆蓋 incrementerFactory (使用Spring Framework提供的標準實現)。 如果它還不能工作,或是你不使用RDBMS,那麼唯一的選擇是讓 SimpleJobRepository 使用Spring方式依賴並且綁定在手工實現的各種Dao接口上。


1.4 Configuring a JobLauncher


JobLauncher 最基本的實現是 SimpleJobLauncher ,它唯一的依賴是通過 JobRepository 獲取一個 execution:

<bean id="jobLauncher"
     class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
     <property name="jobRepository" ref="jobRepository" />
</bean>

一旦獲取到 JobExecution ,那麼可以通過執行 Job 的方法,最終將 JobExecution 返回給調用者.

從調度啓動時,整個序列能夠很好的直接工作,但是,從HTTP請求中啓動則會出現一些問題。在這種場景中,啓動任務需要異步操作,讓SimpleJobLauncher能夠立刻返回結果給調用者,如果讓HTTP請求一直等待很長時間知道批處理任務完成獲取到執行結果,是很糟糕的操作體驗。一個流程如下圖所示:



通過配置 TaskExecutor 可以很容易的將 SimpleJobLauncher 配置成異步操作:

<bean id="jobLauncher"
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
      <property name="jobRepository" ref="jobRepository" />
         <property name="taskExecutor">
         <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
      </property>
</bean>

TaskExecutor 接口的任何實現都能夠用來控制 job 的異步執行。


1.5 Running a Job


運行一個批處理任務至少有兩點要求:一個 JobLauncher 和一個用來運行的 job 。它們都包含了相同或是不同的 context 。舉例來說,從命令行來啓動job,會爲每一個job初始化一個JVM,因此每個job會有一個自己的 JobLauncher;從web容器的HttpRequest來啓動job,一般只是用一個 JobLauncher 來異步啓動job,http請求會調用這個 JobLauncher 來啓動它們需要的job。


1.5.1 在 Web Container 內部運行 Jobs


過去,像批處理任務這樣的離線計算都需要從命令行啓動。但是,許多例子(包括報表、點對點任務和web支持)都表明,從HttpRequest啓動是一個更好的選擇。另外,批處理任務一般都是需要長時間運行,異步啓動時最爲重要的:




這個例子中的Controller就是spring MVC中的Controller(Spring MVC的信息可以在http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html 中查看)。Controller通過使用配置爲異步的(asynchronously)JobLauncher啓動job後立即返回了JobExecution。job保持運行,這個非阻塞的行爲能夠讓controller在持有HttpRequest時立刻返回。示例如下:

@Controller
public class JobLauncherController {
    @Autowired
    JobLauncher jobLauncher;
    @Autowired
    Job job;
    @RequestMapping("/jobLauncher.html")
    public void handle() throws Exception{
      jobLauncher.run(job, new JobParameters());
    }
}

1.6 Meta-Data 高級用法


到目前爲止,已經討論了 JobLauncher 和 JobRepository 接口,它們展示了簡單啓動任務,以及批處理領域對象的基本CRUD操作:



一個JobLauncher使用一個JobRepository創建並運行新的JobExection對象,Job和Step實現隨後使用相同的JobRepository在job運行期間去更新相同的JobExecution對象。這些基本的操作能夠滿足簡單場景的需要,但是對於有着數百個任務和複雜定時流程的大型批處理情況來說,就需要使用更高級的方式訪問元數據:



接下去會討論 JobExplorer 和 JobOperator 兩個接口,能夠使用更多的功能去查詢和修改元數據。

1.6.1 Querying the Repository


在使用高級功能之前,需要最基本的方法來查詢repository去獲取已經存在的 execution 。JobExplored 接口提供了這些功能:

public interface JobExplorer {
    List<JobInstance> getJobInstances(String jobName, int start, int count);
    JobExecution getJobExecution(Long executionId);
    StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId);
    JobInstance getJobInstance(Long instanceId);
    List<JobExecution> getJobExecutions(JobInstance jobInstance);
    Set<JobExecution> findRunningJobExecutions(String jobName);
}


上面的代碼表示的很明顯,JobExplorer是一個只讀版的JobRepository,同JobRepository一樣,它也能夠很容易配置一個工廠類:

<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
       p:dataSource-ref="dataSource" />

之前有提到過,JobRepository 能夠配置不同的表前綴用來支持不同的版本或是schema。JobExplorer 也支持同樣的特性:

<bean id="jobExplorer" class="org.spr...JobExplorerFactoryBean"
      p:dataSource-ref="dataSource" p:tablePrefix="BATCH_" />

1.6.2 JobRegistry


JobRegistry (父接口爲 JobLocator )並非強制使用,它能夠協助用戶在上下文中追蹤job是否可用,也能夠在應用上下文收集在其他地方(子上下文)創建的job信息。自定義的JobRegistry實現常被用於操作job的名稱或是其他屬性。框架提供了一個基於map的默認實現,能夠從job的名稱映射到job的實例:

<bean id="jobRegistry" class="org.spr...MapJobRegistry" />

有兩種方法自動註冊job進JobRegistry:使用bean的post處理器或是使用註冊生命週期組件。這兩種機制在下面描述。

JobRegistryBeanPostProcessor


這是post處理器,能夠將job在創建時自動註冊進JobRegistry:

<bean id="jobRegistryBeanPostProcessor" class="org.spr...JobRegistryBeanPostProcessor">
     <property name="jobRegistry" ref="jobRegistry"/>
</bean>

並不一定要像例子中給post處理器一個id,但是使用id可以在子context中(比如作爲作爲父 bean 定義)也使用post處理器,這樣所有的job在創建時都會自動註冊進JobRegistry。


AutomaticJobRegistrar


這是生命週期組件,用於創建子context以及註冊這些子context中的job。這種做法有一個好處,雖然job的名字仍然要求全局唯一,但是job的依賴項可以不用全局唯一,它可以有一個“自然”的名字。例如,創建了一組xml配置文件,每個文件有一個job,每個job的ItemReader都有一個相同的名字(如"reader"),如果這些文件被導入到一個上下文中,reader的定義會衝突並且互相覆蓋。如果使用了自動註冊機就能避免這一切發生。這樣集成幾個不同的應用模塊就變得更容易了:

<bean class="org.spr...AutomaticJobRegistrar">
     <property name="applicationContextFactories">
        <bean class="org.spr...ClasspathXmlApplicationContextsFactoryBean">
           <property name="resources" value="classpath*:/config/job*.xml" />
        </bean>
     </property>
     <property name="jobLoader">
        <bean class="org.spr...DefaultJobLoader">
            <property name="jobRegistry" ref="jobRegistry" />
        </bean>
     </property>
</bean>

註冊機有兩個主要的屬性,一個是ApplicationContextFactory數組(這兒創建了一個簡單的factory bean),另一個是jobLoader 。JobLoader 負責管理子context的生命週期以及註冊任務到JobRegistry。ApplicationContextFactory 負責創建子 Context,大多數情況下像上面那樣使用
ClassPathXmlApplicationContextFactory。這個工廠類的一個特性是默認情況下他會複製父上下文的一些配置到子上下文。因此如果不變的情況下不需要重新定義子上下文中的 PropertyPlaceholderConfigurer 和AOP配置。
在必要情況下,AutomaticJobRegistrar 可以和 JobRegistyBeanPostProcessor 一起使用。例如,job有可能既定義在父上下文中也定義在子上下文中的情況。


1.6.3 JobOperator


正如前面所討論的,JobRepository 提供了對元數據的 CRUD 操作,JobExplorer 提供了對元數據的只讀操作。然而,這些操作最常用於聯合使用諸多的批量操作類,來對任務進行監測,並完成相當多的任務控制功能,比如停止、重啓或對任務進行彙總。在Spring Batch 中JobOperator 接口提供了這些操作類型:

public interface JobOperator {
      List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException;
      List<Long> getJobInstances(String jobName, int start, int count)throws NoSuchJobException;
      Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException;
      String getParameters(long executionId) throws NoSuchJobExecutionException;
      Long start(String jobName, String parameters)throws NoSuchJobException, JobInstanceAlreadyExistsException;
      Long restart(long executionId)throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
                                 NoSuchJobException, JobRestartException;
      Long startNextInstance(String jobName)throws NoSuchJobException, JobParametersNotFoundException, JobRestartException,
                                 JobExecutionAlreadyRunningException, JobInstanceAlreadyCompleteException;
      boolean stop(long executionId)throws NoSuchJobExecutionException, JobExecutionNotRunningException;
      String getSummary(long executionId) throws NoSuchJobExecutionException;Map<Long, String> getStepExecutionSummaries(long executionId)
                                 throws NoSuchJobExecutionException;
      Set<String> getJobNames();
}

上圖中展示的操作重現了來自其它接口提供的方法,比如JobLauncher, JobRepository, JobExplorer, 以及 JobRegistry。因爲這個原因,所提供的JobOperator的實現SimpleJobOperator的依賴項有很多:

<bean id="jobOperator" class="org.spr...SimpleJobOperator">
    <property name="jobExplorer">
         <bean class="org.spr...JobExplorerFactoryBean">
             <property name="dataSource" ref="dataSource" />
         </bean>
    </property>
    <property name="jobRepository" ref="jobRepository" />
    <property name="jobRegistry" ref="jobRegistry" />
    <property name="jobLauncher" ref="jobLauncher" />
</bean>

注意 如果你在JobRepository中設置了表前綴,那麼不要忘記在JobExplorer中也做同樣設置。

1.6.4 JobParametersIncrementer


JobOperator 的多數方法都是不言自明的,更多詳細的說明可以參見該接口的javadoc(javadoc of the interface)。然而
startNextInstance方法卻有些無所是處。這個方法通常用於啓動Job的一個新的實例。但如果 JobExecution 存在若干嚴重的問題,同時該Job 需要從頭重新啓動,那麼這時候這個方法就相當有用了。不像JobLauncher ,啓動新的任務時如果參數不同於任何以往的參數集,這就要求一個新的 JobParameters 對象來觸發新的 JobInstance,startNextInstance 方法將使用當前的JobParametersIncrementer綁定到這個任務,並強制其生成新的實例:

public interface JobParametersIncrementer {
     JobParameters getNext(JobParameters parameters);
}

JobParametersIncrementer 的協議是這樣的,當給定一個 JobParameters 對象,它將返回填充了所有可能需要的值 “下一個” JobParameters 對象。這個策略非常有用,因爲框架無需知曉變成“下一個”的JobParameters 做了哪些更改。例如,如果任務參數中只包含一個日期參數,那麼當創建下一個實例時,這個值就應該是不是該自增一天?或者一週(如果任務是以周爲單位運行的話)?任何包含數值類參數的任務,如果需要對其進行區分,都涉及這個問題,如下:

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 ”用以區分各個JobInstance。如果當前的JobParameters爲空(null),它將被視爲該Job從未運行過,並同時爲其初始化,然後返回。反之,非空的時候自增一個數值,再返回。自增的數值可以在命名空間描述中通過Job的“incrementer”屬性進行設置:

<job id="footballJob" incrementer="sampleIncrementer"> 
...
</job>

1.6.5 Stopping a Job


JobOperator 最常見的作用莫過於停止某個Job:

Set<Long> executions = jobOperator.getRunningExecutions("sampleJob");
jobOperator.stop(executions.iterator().next());

關閉不是立即發生的,因爲沒有辦法將一個任務立刻強制停掉,尤其是當任務進行到開發人員自己的代碼段時,框架在此刻是無能爲力的,比如某個業務邏輯處理。而一旦控制權還給了框架,它會立刻設置當前 StepExecution 爲 BachStatus.STOPPED ,意爲停止,然後保存,最後在完成前對JobExecution進行相同的操作。


1.6.6 Aborting a Job


一個job的執行過程當執行到FAILED狀態之後,如果它是可重啓的,它將會被重啓。如果任務的執行過程狀態是ABANDONED,那麼框架就不會重啓它。ABANDONED狀態也適用於執行步驟,使得它們可以被跳過,即便是在一個可重啓的任務執行之中:如果任務執行過程中碰到在上一次執行失敗後標記爲ABANDONED的步驟,將會跳過該步驟直接到下一步(這是由任務流定義和執行步驟的退出碼決定的)。

如果當前的系統進程死掉了(“kill -9”或系統錯誤),job自然也不會運行,但JobRepository是無法偵測到這個錯誤的,因爲進程死掉之前沒有對它進行任何通知。你必須手動的告訴它,你知道任務已經失敗了還是說考慮放棄這個任務(設置它的狀態爲FAILED或ABANDONED)-這是業務邏輯層的事情,無法做到自動決策。只有在不可重啓的任務中才需要設置爲FAILED狀態,或者你知道重啓後數據還是有效的。Spring Batch Admin中有一系列工具JobService,用以取消正在進行執行的任務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章