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"

在这里插入图片描述
BATCH_JOB_EXECUTION_PARAMS: 记录作业执行参数。

在这里插入图片描述

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

  • @StepScope:延时加载Bean,项目启动时不加载Bean,等到实际调用时才去加载该Bean。
  • @Value("#{jobParameters['timestamp']}":获取作业参数。
  • @Value("#{jobParameters['变量名']}"):获取jobParameters中指定变量的值。
  • @Value("#{stepExecutionContext['file']}"): 获取步骤执行上下文中的值。
@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;
        }
    };
}

三:@JobScope

  • @Value("#{jobParameters['timestamp']}":获取作业参数。
  • @Value("#{jobExecutionContext['file']}"):获取作业执行上下文中的值。
@Bean
@JobScope
public FlatFileItemReader flatFileItemReader(@Value("#{jobExecutionContext['file']}") String file) {
    return new FlatFileItemReaderBuilder<User>()
            .name("xxx")
            .resource(new FileSystemResource(file))
            .build();
}

四:命令行传参

传参可以在运行作业时通过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;
        }
    };
}

在这里插入图片描述

五:作业参数增量器 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个作业实例。
在这里插入图片描述

BATCH_JOB_EXECUTION_PARAMS表中有2条,同一个作业jobName对应的run.id值是累加的,不同的作业实例会从1开始。
在这里插入图片描述

六:默认参数校验器 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;
}

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风流 少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值