Spring Batch 使用(二)

227 阅读4分钟

多步骤执行

@Configuration
public class BatchTestMultiJob {

    //任务工厂
    private final JobBuilderFactory jobBuilderFactory;
    //步骤工厂
    private final StepBuilderFactory stepBuilderFactory;

    public BatchTestMultiJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
    }

    @Bean
    public Job multiJob1() {
        //创建一个名为BatchTestMultiJob的job,multiStep1,2,3放入这个任务中
        return jobBuilderFactory.get("BatchTestMultiJob")
                //执行step1,2,3
                .start(multiStep1())
                .next(multiStep2())
                .next(multiStep3())
                .build();
    }

    @Bean
    public Step multiStep1() {
        //创建一个名为multiStep1的step
        return stepBuilderFactory.get("multiStep1").tasklet((stepContribution, chunkContext) -> {
            System.out.println("step1 OK!");
            // 返回本次step的执行状态
            return RepeatStatus.FINISHED;
        }).build();
    }

    @Bean
    public Step multiStep2() {
        //创建一个名为multiStep2的step
        return stepBuilderFactory.get("multiStep2").tasklet((stepContribution, chunkContext) -> {
            System.out.println("step2 OK!");
            // 返回本次step的执行状态
            return RepeatStatus.FINISHED;
        }).build();
    }

    @Bean
    public Step multiStep3() {
        //创建一个名为multiStep3的step
        return stepBuilderFactory.get("multiStep3").tasklet((stepContribution, chunkContext) -> {
            System.out.println("step3 OK!");
            // 返回本次step的执行状态
            return RepeatStatus.FINISHED;
        }).build();
    }
}
执行结果

依次输出step1,step2,step3
image.png

Flow串行

Flow可以将多个step串起来,变成一个集合执行,多个step顺序执行

@Configuration
public class BatchFlowTestJob {
    //任务工厂
    private final JobBuilderFactory jobBuilderFactory;
    //步骤工厂
    private final StepBuilderFactory stepBuilderFactory;

    public BatchFlowTestJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
    }

    @Bean
    public Job flowJob() {
        return jobBuilderFactory.get("flowJob")
                .start(flow())
                .end()
                .build();
    }

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

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

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

    @Bean
    public Flow flow() {
        return new FlowBuilder<Flow>("myFlow")
                .start(flow1())
                .next(flow2())
                .next(flow3())
                .build();
    }
}
执行结果

按照Job中的顺序输出
顺序输出

Split并行

当出现有大量数据处理时间较长时,可以使用异步并行处理

@Configuration
public class BatchSplitTestJob {
    //任务工厂
    private final JobBuilderFactory jobBuilderFactory;
    //步骤工厂
    private final StepBuilderFactory stepBuilderFactory;

    public BatchSplitTestJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
    }

    @Bean
    public Job flowSplitJob() {
        Flow flowSplit1 = new FlowBuilder<Flow>("flowSplit1").start(split1()).build();
        Flow flowSplit2 = new FlowBuilder<Flow>("flowSplit1").start(split2()).build();
        return jobBuilderFactory.get("flowSplitJob")
                .flow(split3())
                .split(new SimpleAsyncTaskExecutor()).add(flowSplit1,flowSplit2)//flowSplit1,flowSplit2加入异步任务执行器
                .end()
                .build();
    }

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

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

    @Bean
    public Step split3() {
        return stepBuilderFactory.get("split3")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("split3执行。。。");
                    return RepeatStatus.FINISHED;
                }).build();
    }
}
执行结果

因为是异步执行,所以是乱序输出
异步执行

Decider决策器

自定义一个决策器,来决定执行哪个step
创建一个决策器,默认开关打开,决策器返回状态为'switch-open'

@Component
public class MyDecider implements JobExecutionDecider {
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        boolean switchFlag = true;
        if (switchFlag) {
            return new FlowExecutionStatus("switch-open");
        }else {
            return new FlowExecutionStatus("switch-close");
        }
    }
}

创建Job,包含step1,2,3,并将自定义的decider注入进来。
如果决策器返回switch-open,执行step2
如果决策器返回switch-close,执行step3

@Configuration
public class BatchTestDeciderJob {

    //任务工厂
    private final JobBuilderFactory jobBuilderFactory;
    //步骤工厂
    private final StepBuilderFactory stepBuilderFactory;

    private final MyDecider decider;

    public BatchTestDeciderJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, MyDecider decider) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.decider = decider;
    }

    @Bean
    public Job deciderJob1() {
        //创建一个名为BatchTestDeciderJob的job,decider1,2,3放入这个任务中
        return jobBuilderFactory.get("BatchTestDeciderJob")
                //执行step1,2,3
                .start(deciderStep1())
                .next(decider)
                //如果决策其返回状态为"switch-open",执行step2
                .from(decider).on("switch-open").to(deciderStep2())
                //如果决策其返回状态为"switch-close",执行step3
                .from(decider).on("switch-close").to(deciderStep3())
                .end()
                .build();
    }

    @Bean
    public Step deciderStep1() {
        //创建一个名为deciderStep1的step
        return stepBuilderFactory.get("deciderStep1").tasklet((stepContribution, chunkContext) -> {
            System.out.println("step1 OK!");
            // 返回本次step的执行状态
            return RepeatStatus.FINISHED;
        }).build();
    }

    @Bean
    public Step deciderStep2() {
        //创建一个名为deciderStep2的step
        return stepBuilderFactory.get("deciderStep2").tasklet((stepContribution, chunkContext) -> {
            System.out.println("step2 OK!");
            // 返回本次step的执行状态
            return RepeatStatus.FINISHED;
        }).build();
    }

    @Bean
    public Step deciderStep3() {
        //创建一个名为deciderStep3的step
        return stepBuilderFactory.get("deciderStep3").tasklet((stepContribution, chunkContext) -> {
            System.out.println("step3 OK!");
            // 返回本次step的执行状态
            return RepeatStatus.FINISHED;
        }).build();
    }
}
执行结果

执行了step1和step2,没有执行step3
image.png

任务嵌套

我们可以将Job转换成特殊的step,再将转换后的step放入Job中执行,这种方式称之为任务的嵌套。

示例中先创建了两个job:childJob1,childJob2。再将这两个Job转换成了特殊的Step:childJobStep1,childJobStep2。最后将Step:childJobStep1,Step:childJobStep2放入到mainJob中执行

@Configuration
public class BatchTestNestJob {

    //任务工厂
    private final JobBuilderFactory jobBuilderFactory;
    //步骤工厂
    private final StepBuilderFactory stepBuilderFactory;

    private final JobLauncher jobLauncher;

    private final JobRepository jobRepository;

    private final   PlatformTransactionManager platformTransactionManager;


    public BatchTestNestJob(JobBuilderFactory jobBuilderFactory,
                            StepBuilderFactory stepBuilderFactory,
                            JobLauncher jobLauncher,
                            JobRepository jobRepository,
                            PlatformTransactionManager platformTransactionManager) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.jobLauncher = jobLauncher;
        this.jobRepository = jobRepository;
        this.platformTransactionManager = platformTransactionManager;
    }

    @Bean
    public Job mainJob() {
        //创建一个名为mainJob的job,将包含子job的step放入这个任务中
        return jobBuilderFactory.get("mainJob")
                //执行step1,2,3
                .start(childJobStep1())
                .next(childJobStep2())
                .build();
    }

    //创建job1,包含step1
   @Bean
    public Job childJob1() {
        return jobBuilderFactory.get("childJob1")
                .start(
                        stepBuilderFactory.get("childJobStep1")
                                .tasklet((stepContribution, chunkContext) -> {
                                    System.out.println("子任务一执行");
                                    return RepeatStatus.FINISHED;
                                }).build()
                ).build();
    }

    //创建job2,包含step2
    @Bean
    public Job childJob2() {
        return jobBuilderFactory.get("childJob2")
                .start(
                        stepBuilderFactory.get("childJobStep2")
                                .tasklet((stepContribution, chunkContext) -> {
                                    System.out.println("子任务二执行");
                                    return RepeatStatus.FINISHED;
                                }).build()
                ).build();
    }
    //将childJob1转换成childJobStep1
    @Bean
    public Step childJobStep1() {
        return new JobStepBuilder(new StepBuilder("childJobStep1"))
                .job(childJob1())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(platformTransactionManager)
                .build();
    }

    //将childJob2转换成childJobStep2
    @Bean
    public Step childJobStep2() {
        return new JobStepBuilder(new StepBuilder("childJobStep2"))
                .job(childJob2())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(platformTransactionManager)
                .build();
    }
}
执行结果

可以发现最先定义的子Job中的childJobStep1,childJobStep2按顺序执行成功
image.png