Spring Batch:自定义ExitStatus下JobExecutionDecider失效求助
问题:Spring Batch流程执行initialStep后直接失败,未进入决策器及后续步骤
需求说明
- 通过initialStep读取Job参数中的输入文件名,判断是否包含特定字符串
- 若包含则进入process步骤,若不包含则进入failedStep
编写的代码
初始步骤与监听器
@Bean public Step initialStep() { return stepBuilderFactory.get("initialStep") .tasklet((contribution, chunkContext) -> { System.out.println("INTIAL STEP"); return RepeatStatus.FINISHED; }).listener(stepExecutionListener()).build(); } @Bean public StepExecutionListener stepExecutionListener() { return new MyStepExecutionListener(); } static class MyStepExecutionListener implements StepExecutionListener { @Override public void beforeStep(StepExecution stepExecution) { System.out.println("MyStepExecutionListener.beforeStep"); } @Override public ExitStatus afterStep(StepExecution stepExecution) { var inputFileName = stepExecution.getJobParameters().getString("inputFileName"); System.out.println("MyStepExecutionListener.afterStep"); if (inputFileName != null && (inputFileName.contains("abc"))) { return new ExitStatus("YES", "For processing step"); } return new ExitStatus("NO", "For failed step"); } }
决策器代码
@Bean public JobExecutionDecider decider() { return (jobExecution, stepExecution) -> { System.out.println(stepExecution.getExitStatus().getExitCode()); if("YES".equals(stepExecution.getExitStatus().getExitCode())) { return new FlowExecutionStatus("YES"); } else { return new FlowExecutionStatus("NO"); } }; }
其他步骤代码
@Bean public Step process() { return stepBuilderFactory.get("process") .tasklet((contribution, chunkContext) -> { //logic to process return RepeatStatus.FINISHED; }).build(); } @Bean public Step failedStep() { return stepBuilderFactory.get("failedStep") .tasklet((contribution, chunkContext) -> { return RepeatStatus.FINISHED; }).build(); }
Job配置代码
@Bean Job job() throws Exception { return jobBuilderFactory .get("job") .incrementer(new RunIdIncrementer()) .start(initialStep()) .next(decider()).on("YES").to(process()) .from(decider()).on("NO").to(failedStep()).end() .build(); }
运行错误日志
2023-04-03 15:41:42.865 INFO 17532 --- [ restartedMain] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=job]] launched with the following parameters: [{RunDate=2023-04-03T15:41:41.080044100}] 2023-04-03 15:41:44.656 INFO 17532 --- [ restartedMain] o.s.batch.core.job.SimpleStepHandler : Executing step: [initialStep] MyStepExecutionListener.beforeStep INTIAL STEP MyStepExecutionListener.afterStep 2023-04-03 15:42:04.078 INFO 17532 --- [ restartedMain] o.s.batch.core.step.AbstractStep : Step: [initialStep] executed in 19s422ms 2023-04-03 15:42:04.868 INFO 17532 --- [ restartedMain] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=job]] completed with the following parameters: [{RunDate=2023-04-03T15:41:41.080044100}] and the following status: [FAILED] in 21s652ms
问题原因与解决方案
问题根源
- Spring Batch默认仅将
ExitStatus.COMPLETED视为步骤成功状态,你返回的YES/NO属于自定义状态,未被声明为允许流转的状态,因此被判定为步骤失败,直接终止Job。 - Job配置的流转链式调用存在逻辑漏洞,未正确衔接initialStep的自定义状态到决策器。
修正方案一:调整Job配置,允许自定义状态流转
修改Job配置,显式声明YES/NO为合法流转状态,确保步骤执行后能进入决策器:
@Bean Job job() throws Exception { return jobBuilderFactory .get("job") .incrementer(new RunIdIncrementer()) .start(initialStep()) .on("YES", "NO").to(decider()) // 允许这两个自定义状态流转到决策器 .from(decider()).on("YES").to(process()) .from(decider()).on("NO").to(failedStep()) .end() .build(); }
修正方案二:简化逻辑,直接在决策器中处理参数
无需通过StepListener传递状态,直接在决策器内读取Job参数做判断,避免状态流转问题:
// 重构决策器 @Bean public JobExecutionDecider decider() { return (jobExecution, stepExecution) -> { String inputFileName = jobExecution.getJobParameters().getString("inputFileName"); if (inputFileName != null && inputFileName.contains("abc")) { return new FlowExecutionStatus("YES"); } return new FlowExecutionStatus("NO"); }; } // 简化Job配置 @Bean Job job() throws Exception { return jobBuilderFactory .get("job") .incrementer(new RunIdIncrementer()) .start(initialStep()) .next(decider()) .on("YES").to(process()) .on("NO").to(failedStep()) .end() .build(); }
额外注意事项
- 运行Job时必须传入
inputFileName参数,否则会因参数null进入failedStep分支。 - 若initialStep无额外业务逻辑,可直接从决策器启动Job,进一步简化代码。
内容的提问来源于stack exchange,提问作者Vamsi
相关产品推荐
相关产品推荐

