SpringBatch从入门到实战(三):作业参数

一:API获取作业参数

Spring Batch认为一个Job的唯一依据是 job_name + hash(JobParameters) 作为联合主键 。如果每次执行都会传入一个唯一变动的参数(如时间戳、自增ID等),spring batch 就会认为这是不同的job,这样同一个jobName就可以重复执行了。

@RequestMapping("/start")
public ExitStatus start() throws Exception {
    JobParameters jobParameters = new JobParametersBuilder()
            .addLong("timestamp", new Date().getTime())
            .toJobParameters();
    JobExecution jobExecution = jobLauncher.run(job, jobParameters);
    return jobExecution.getExitStatus();
}

@Bean
public Tasklet hellWorldTasklet() {
    return new Tasklet() {
        @Override
        public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
            Map<String, Object> jobParameters = chunkContext.getStepContext().getJobParameters();
            // 1686233766695 hello world spring batch
            System.out.println(jobParameters.get("timestamp") + " hello world spring batch");
            return RepeatStatus.FINISHED;
        }
    };
}

每次调用的timestamp值都不一样,都会看做是不同的作业,调用两次: http://localhost:8080/job/start ,两次都是 "exitCode": "COMPLETED"

SpringBatch从入门到实战(三):作业参数_第1张图片
BATCH_JOB_EXECUTION_PARAMS: 记录作业执行参数。

在这里插入图片描述

二:注解获取参数 @StepScope + @Value

  • @StepScope:延时加载Bean,项目启动时不加载Bean,等到实际调用时才去加载该Bean。
  • @Value("#{jobParameters['变量名']}"):获取jobParameters中指定变量的值。
@Bean
public Step hellWorldStep() {
    return stepBuilderFactory.get("hellWorldStep")
    		// 传参传null即可,实际会通过@Value注入的
            .tasklet(hellWorldTasklet(null))
            .build();
}

@Bean
@StepScope
public Tasklet hellWorldTasklet(@Value("#{jobParameters['timestamp']}") Long timestamp) {
    return new Tasklet() {
        @Override
        public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
            System.out.println(timestamp + " hello world spring batch");
            return RepeatStatus.FINISHED;
        }
    };
}

三:命令行传参

传参可以在运行作业时通过jobParameters传参,也可以通过命令行方式传参,
注意:命令行方式传参不能通过手动启动作业,必须通过启动程序时自动执行作业才可以获取到参数,即spring.batch.job.enabled = true

@Bean
@StepScope
public Tasklet hellWorldTasklet() {
    return new Tasklet() {
        @Override
        public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
        	// key1:value1
        	// key2:value2
            Map<String, Object> jobParameters = chunkContext.getStepContext().getJobParameters();
            return RepeatStatus.FINISHED;
        }
    };
}

SpringBatch从入门到实战(三):作业参数_第2张图片

四:作业参数增量器 RunIdIncrementer

通过往JobParameters增加时间戳参数timestamp是可以解决同一个Job执行多次的问题,但是编程不够优雅,SpringBatch提供了一种自增ID的实现。

RunIdIncrementer会自动往JobParameters中添加一个参数run.id,值为从1累加的。通过使用RunIdIncrementer也可以做到同一个作业允许重复运行多次。通过 incrementer(JobParametersIncrementer jobParametersIncrementer ) 方法设置。

@Bean
public Job helloWorldJob() {
    return jobBuilderFactory.get("helloWorldJob")
            .start(hellWorldStep())
            // 配置作业参数增量器
            .incrementer(new RunIdIncrementer())
            .build();
}

注意:spring.batch.job.enabled=true时incrementer是直接生效的。

@RequestMapping("/start")
public ExitStatus start() throws Exception {
	// 这里传一个空的JobParameters对象即可
    JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
    return jobExecution.getExitStatus();
}

如果spring.batch.job.enabled=false,通过手动触发时需要先借助JobExplorer先获取run.id,然后再通过RunIdIncrementer去自增累加。

@RestController
@RequestMapping("/job")
public class JobController {
    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private JobExplorer jobExplorer;

    @Autowired
    private Job job;


    @RequestMapping("/start")
    public ExitStatus start() throws Exception {
    	// RunIdIncrementer 需要配合JobExplorer使用
        JobParameters jobParameters = new JobParametersBuilder(jobExplorer)
                .getNextJobParameters(job)
                .toJobParameters();
        JobExecution jobExecution = jobLauncher.run(job, jobParameters);
        return jobExecution.getExitStatus();
    }
}

执行两次作业就被看成2个作业实例。
SpringBatch从入门到实战(三):作业参数_第3张图片

BATCH_JOB_EXECUTION_PARAMS表中有2条,同一个作业jobName对应的run.id值是累加的,不同的作业实例会从1开始。
SpringBatch从入门到实战(三):作业参数_第4张图片

五:默认参数校验器 DefaultJobParametersValidator

DefaultJobParametersValidator是Spring Batch提供的用于校验参数必选可选的校验,校验不通过抛出异常不执行Job, JobParametersInvalidException: The JobParameters do not contain required keys: [file],注意如果配置了RunIdIncrementer,setRequiredKeys也要设置"run.id"

  • setRequiredKeys:设置必传参数。
  • setOptionalKeys:设置可选参数。
@Bean
public Job helloWorldJob() {
    return jobBuilderFactory.get("helloWorldJob")
            .start(hellWorldStep())
            .incrementer(new RunIdIncrementer())
            .validator(defaultJobParametersValidator())
            .build();
}


@Bean
public DefaultJobParametersValidator defaultJobParametersValidator() {
    DefaultJobParametersValidator defaultJobParametersValidator = new DefaultJobParametersValidator();
    defaultJobParametersValidator.setRequiredKeys(new String[]{"run.id", "file"});
    defaultJobParametersValidator.setOptionalKeys(new String[]{"date"});
    return defaultJobParametersValidator;
}

六:自定义作业参数校验器 JobParametersValidator

实现 JobParametersValidator 接口,当不满足条件时抛出异常 JobParametersInvalidException , 通过validator()设置校验器。

public class MyJobParametersValidator implements JobParametersValidator {
    @Override
    public void validate(JobParameters jobParameters) throws JobParametersInvalidException {
        Long timestamp = jobParameters.getLong("timestamp");
        if (timestamp < new Date().getTime()) {
            throw new JobParametersInvalidException("timestamp参数错误");
        }
    }
}
@Bean
public Job helloWorldJob() {
    return jobBuilderFactory.get("helloWorldJob")
            .start(hellWorldStep())
            .validator(jobParametersValidator())
            .build();
}

@Bean
public JobParametersValidator jobParametersValidator() {
    return new MyJobParametersValidator();
}

七:组合作业参数校验器 CompositeJobParametersValidator

将多个作业参数校验器封装成一个作业校验器,只有所有校验器通过才算整个校验器通过。

@Bean
public Job helloWorldJob() {
    return jobBuilderFactory.get("helloWorldJob")
            .start(hellWorldStep())
            .incrementer(new RunIdIncrementer())
            .validator(compositeJobParametersValidator())
            .build();
}


@Bean
public CompositeJobParametersValidator compositeJobParametersValidator() {
    DefaultJobParametersValidator defaultJobParametersValidator = new DefaultJobParametersValidator();
    defaultJobParametersValidator.setRequiredKeys(new String[]{"run.id", "file"});
    defaultJobParametersValidator.setOptionalKeys(new String[]{"date"});

    MyJobParametersValidator myJobParametersValidator = new MyJobParametersValidator();

    CompositeJobParametersValidator compositeJobParametersValidator = new CompositeJobParametersValidator();
    compositeJobParametersValidator.setValidators(Arrays.asList(defaultJobParametersValidator, myJobParametersValidator));
    return compositeJobParametersValidator;
}

八:你跟着乞丐,你就只能学要饭!

靠体力为生永远都是不可取的,

骆驼祥子在离世的那天,
他以为说多拉几趟车,
就能过上更好的生活。

其实人到了错误的环境下,
接触了错误的人,
遇见了错误的事儿和理论,
这个时候,
即使你再有能力,
即使你再善良,
都没有用的。

其实老人们说的那句话还是很有道理的,
就是:你跟着千万赚百万,你跟着乞丐,你就只能学要饭。

你可能感兴趣的:(Spring,SpringBatch作业参数)