1. 程式人生 > >Spring Batch 之 flow 介紹和使用

Spring Batch 之 flow 介紹和使用

         通過前文我們已經知道,Step 是一個獨立的、順序的處理步驟,包含完整的輸入、處理以及輸出。但是在企業應用中,我們面對的更多情況是多個步驟按照一定的順序進行處理。因此如何維護步驟之間的執行順序是我們需要考慮的。Spring Batch 提供了 Step Flow 來解決這個問題。

         在介紹之前需要先了解SpringBatch中的BatchStatus和ExitStatus這兩個狀態的含義。


BatchStatus和ExitStatus含義


1.BatchStatus:批處理狀態
批處理狀態是由批處理框架使用,用來記錄Job、Step的執行情況。SpringBatch的重啟即是利用了BatchStauts來實現。對應BATCH_JOB_INSTANCE和BATCH_STEP_EXECUTION表中的STATUS欄位值。

JobExecution.getStatus()獲取作業Job批處理狀態;

StepExecution.getStatus()獲取作業Step的批處理狀態;

 

2.ExitStatus:退出狀態

退出狀態表示Step執行後或者Job執行後的狀態,該值要以被修改,通常用於條件Flow中。

可以通過攔截器StepExecutionListener的afterStep方法來修改退出狀態;

對應BATCH_JOB_INSTANCE和BATCH_STEP_EXECUTION表中的EXIT_CODE欄位值;

 

               狀態                                       說明
     COMPLETED 完成,所有Step都處理該狀態,則JOB會處理該狀態
     STARTING 表示作業正在啟動,還沒有啟動完畢
     STARTED 表示作業啟動完成
      STOPING 表示作業正在停止中
     STOPED 表示作業停止完成
      FAILED 表示作業執行失敗
  ABANDONED 表示當前下次重啟JOB時需要廢棄的Step,即不會被再次執行
    UNKOWN 表示未知錯誤,該狀態下重啟Job會拋錯

 

順序Flow  Demo:

package com.batch.demo.flow.jobFlowDemoTwo;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.builder.FlowBuilder;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JobFlowDemoTwoConfiguration {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Step jobFlowDemoTwoStep1(){
        return stepBuilderFactory.get("jobFlowDemoTwoStep1")
                .tasklet(((stepContribution, chunkContext) -> {
                    System.out.println("jobFlowDemoTwoStep1");
                    return RepeatStatus.FINISHED;
                })).build();
    }

    @Bean
    public Step jobFlowDemoTwoStep2(){
        return stepBuilderFactory.get("jobFlowDemoTwoStep2")
                .tasklet(((stepContribution, chunkContext) -> {
                    System.out.println("jobFlowDemoTwoStep2");
                    return RepeatStatus.FINISHED;
                })).build();
    }

    @Bean
    public Step jobFlowDemoTwoStep3(){
        return stepBuilderFactory.get("jobFlowDemoTwoStep3")
                .tasklet(((stepContribution, chunkContext) -> {
                    System.out.println("jobFlowDemoTwoStep3");
                    return RepeatStatus.FINISHED;
                })).build();
    }

    @Bean
    public Flow jobFlowDemoFlow1(){
        return new FlowBuilder<Flow>("jobFlowDemoFlow1")
                .start(jobFlowDemoTwoStep1())
                .next(jobFlowDemoTwoStep2())
                .build();
    }

    @Bean
    public Job jobFlowDemoTwoJob(){
        return jobBuilderFactory.get("jobFlowDemoTwoJob")
                .start(jobFlowDemoFlow1())
                .next(jobFlowDemoTwoStep3()).end()
                .build();
    }
}

 

根據動態自定義Decider 決定Flow 執行順序 Demo:

1.自定義一個MyDecider, 根據呼叫次數,技術返回“EVEN”,偶數返回“ODD”;

package com.batch.demo.flow.flowDecisionDemo;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;

public class MyDecider implements JobExecutionDecider {
    private int count = 0;
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        count ++;
        if (count % 2 == 0)
            return new FlowExecutionStatus("EVEN");
        else
            return new FlowExecutionStatus("ODD");
    }
}

2. job中呼叫MyDecider,當返回“EVEN”時,呼叫evenStep;當返回“ODD”時,呼叫oddStep。

package com.batch.demo.flow.flowDecisionDemo;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FlowDecisionDemoConfiguration {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Step firstStep(){
        return stepBuilderFactory.get("firstStep")
                .tasklet(((stepContribution, chunkContext) -> {
                    System.out.println("firstStep");
                    return RepeatStatus.FINISHED;
                })).build();
    }

    @Bean
    public Step oddStep(){
        return stepBuilderFactory.get("oddStep")
                .tasklet(((stepContribution, chunkContext) -> {
                    System.out.println("oddStep");
                    return RepeatStatus.FINISHED;
                })).build();
    }

    @Bean
    public Step evenStep(){
        return stepBuilderFactory.get("evenStep")
                .tasklet(((stepContribution, chunkContext) -> {
                    System.out.println("evenStep");
                    return RepeatStatus.FINISHED;
                })).build();
    }

    @Bean
    public JobExecutionDecider myDecider(){
        return new MyDecider();
    }

    @Bean
    public Job flowDecisonDemoJob(){
        return jobBuilderFactory.get("flowDecisonDemoJob").start(firstStep())
                .next(myDecider())
                .from(myDecider()).on("EVEN").to(evenStep())
                .from(myDecider()).on("ODD").to(oddStep())
                .from(oddStep()).on("*").to(myDecider())
                .end()
                .build();
    }


}