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();
}
}