How to use decider in Spring batch?

て烟熏妆下的殇ゞ 提交于 2019-12-10 12:18:27

问题


I'm new to Spring batch. I've created a decider which returns a FlowExecutionStatus as "YES" / "NO". Based on the FlowExecutionStatus, I need to call step2() or step3().

In my below code, step2() is getting called before decider. How to modify the code so that decider will be called and based on the "FlowExecutionStatus" returned bu the decider, either step2() or step3() should be called. Please help.

@Autowired
private NumberDecider decider;

@Bean
public Job NumberLoaderJob() throws NumberFormatException, IOException {
    return jobBuilderFactory.get("numberLoaderJob").start(step1()).listener(new MyNumberJobListener())
            .next(decider).on("YES").to(step2())
            .from(decider).on("NO").to(step3()).end().build();
}

    @Bean
public Step step1() {

    return stepBuilderFactory.get("step1").tasklet(new Tasklet() {

        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
            System.out.println("Exiting step1() execute()");
            return RepeatStatus.FINISHED;
        }
    }).build();
}

/**
 * Step 2
 * 
 * @return
 * @throws NumberFormatException
 * @throws IOException
 */
@Bean
public Step step2() throws NumberFormatException, IOException {
    return stepBuilderFactory.get("step2").listener(new MyStepListener())
            .<OrderNumber, OrderNumber>chunk(Integer.valueOf(chunkSize)).faultTolerant()
            .listener(new MyChunkListener()).reader(new MyItemReader())
            .listener(new MyItemReaderListener()).writer(customItemWriter())
            .listener(new MyWriteListener()).build();
}

回答1:


You would need to to set the exit status in step1 so that the decider picks it up and make the decision:

@Bean
public Step step1() {

   return stepBuilderFactory.get("step1").tasklet(new Tasklet() {

       @Override
       public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
          System.out.println("Exiting step1() execute()");
          chunkContext.getStepContext().getStepExecution().setExitStatus(new ExitStatus("YES")); // or NO
          return RepeatStatus.FINISHED;
       }

    }).build();
}

EDIT: I thought that the decider should make the decision based on the exit status of step1, hence the previous sample. So adding a sample to show how to use a decider (after clarification):

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public Step step1() {
        return steps.get("step1")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("hello");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public JobExecutionDecider decider() {
        return (jobExecution, stepExecution) -> new FlowExecutionStatus("YES"); // or NO
    }

    @Bean
    public Step step2() {
        return steps.get("step2")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("world");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step step3() {
        return steps.get("step3")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("!!");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(step1())
                .next(decider())
                    .on("YES").to(step2())
                    .from(decider()).on("NO").to(step3())
                    .end()
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }

}

In this example, step1 is executed first, then the decider. If the decider returns YES, step2 is executed and if returns NO, step3 is executed.

Hope this helps.



来源:https://stackoverflow.com/questions/52168976/how-to-use-decider-in-spring-batch

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!