通过前文我们已经知道,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();
}
}