Spring Batch4 Job 参数的使用

前面章节提供的所有示例的 Step 实现中均是简单的输出一段文本到控制台,然而真实场景中不可能如此简单。通常我们在启动一个 Job 的时候,或多或少都会携带一部分参数过去。在 Spring Batch4 核心概念 章节指出,我们通常使用“Job + JobParameters”来唯一确定 JobInstance 对象。如下图:

Spring Batch4 Job 参数的使用

上图存在两个 JobParameters,它们内部保存了一个 date 字段。因此,也就存在两个 JobInstance,本章将详细介绍 JobParameters。

在 Spring Batch 4 中,JobParameters 用于封装作业执行时所需参数的核心组件。它为作业提供了参数化执行的能力,并确保作业实例的唯一性。

  

JobParameters 的定义

JobParameters 表示批处理作业运行时参数的值(Value)对象。由于这些参数在其所包含的 JobParameters 之外没有单独的意义,因此它是一个值(Value)对象而非实体。为了确定一个 JobParameters 对象是否等于另一个,参数对象能够可靠地与另一个进行相等性比较也极为重要。此外,由于这些参数需要被持久化,因此限制所添加的类型至关重要。

注意,一个 Job 通常需要多个参数,因此在 JobParameters 内部使用一个 Map 来保存 Job 的所有参数,Map 的定义如下:

private final Map<String,JobParameter> parameters;

如下图:

image.png

下面是 JobParameters 的部分源码:

package org.springframework.batch.core;

import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import org.springframework.lang.Nullable;

@SuppressWarnings("serial")
public class JobParameters implements Serializable {
    // 内部存储的参数
    private final Map<String,JobParameter> parameters;

    public JobParameters() {
       this.parameters = new LinkedHashMap<>();
    }

    public JobParameters(Map<String,JobParameter> parameters) {
       this.parameters = new LinkedHashMap<>(parameters);
    }

    /**
     * 针对所提供 key 对应的 Long 类型值的类型安全获取方法。
     * @param key 要获取值得 key
     * @return Long 值,如果 key 不存在,则返回 null
     */
    @Nullable
    public Long getLong(String key){
       if (!parameters.containsKey(key)) {
          return null;
       }
       Object value = parameters.get(key).getValue();
       return value==null ? null : ((Long)value).longValue();
    }

    // ...为了节省篇幅,将其他 getXXX() 方法省略...

    /**
     * 获取所有参数,包含 string, long, date...
     * 
     * @return 一个包含所有参数的不可修改的 Map。
     */
    public Map<String, JobParameter> getParameters(){
       // 使用 Collections.unmodifiableMap() 方法修饰 Map,Map 不允许被修改,
       return Collections.unmodifiableMap(parameters);
    }

    /**
     * 判断参数是否为空
     * @return 如果参数为空则返回true,否则返回false。
     */
    public boolean isEmpty(){
       return parameters.isEmpty();
    }

    @Override
    public boolean equals(Object obj) {
       if(obj instanceof JobParameters == false){
          return false;
       }

       if(obj == this){
          return true;
       }

       JobParameters rhs = (JobParameters)obj;
       return this.parameters.equals(rhs.parameters);
    }

    @Override
    public int hashCode() {
       return 17 + 23 * parameters.hashCode();
    }

    @Override
    public String toString() {
       return parameters.toString();
    }

    // 将参数转换成 Properties
    public Properties toProperties() {
       Properties props = new Properties();

       for (Map.Entry<String, JobParameter> param : parameters.entrySet()) {
          if (param.getValue() != null) {
             props.put(param.getKey(), Objects.toString(param.getValue().toString(), ""));
          }
       }

       return props;
    }
}

 

JobParameter 的定义

从上面可以知道,JobParameter 是被包含在 JobParameters 内部的 Map<String,JobParameter> 中,一个 JobParameter 代表一个具体的参数。

JobParameter 是批量作业参数的域表示。只有以下类型可以作为参数:字符串(String)、长整型(Long)、日期(Date)和双精度型(Double)。其中,识别标志用于指示该参数是否用作 JobInstance(作业实例)标识的一部分。 

JobParameter 还是一个不可变值对象。

下面是 JobParameter 的部分源码:

package org.springframework.batch.core;

import java.io.Serializable;
import java.util.Date;

@SuppressWarnings("serial")
public class JobParameter implements Serializable {
    // 参数值
    private final Object parameter;
    // 参数类型
    private final ParameterType parameterType;
    // 参数是否作为 JobInstance 标识的一部分
    private final boolean identifying;

    /**
     * 使用字符串构造一个新的 JobParameter 
     * @param parameter 字符串实例
     * @param identifying true标识作为标识的一部分,false不是。
     */
    public JobParameter(String parameter, boolean identifying) {
       this.parameter = parameter;
       parameterType = ParameterType.STRING;
       this.identifying = identifying;
    }

    // 省略其他类型的构造方法,如 Long、Date、Double 等等...
    
    // 获取标识值
    public boolean isIdentifying() {
       return identifying;
    }

    /**
     * 获取实际的参数值
     * @return the value contained within this JobParameter.
     */
    public Object getValue() {
       // 如果是 Date 类型,则返回毫秒数
       if (parameter != null && parameter.getClass().isInstance(Date.class)) {
          return new Date(((Date) parameter).getTime());
       }
       else {
          return parameter;
       }
    }

    /**
     * 获取参数类型
     * @return a ParameterType representing the type of this parameter.
     */
    public ParameterType getType() {
       return parameterType;
    }

    // 省略 equals 和 hasCode

    /**
     * 标识 JobParameter 类型的枚举
     */
    public enum ParameterType {
       STRING, DATE, LONG, DOUBLE;
    }
}

  

简单示例

下面通过一个简单的示例演示如何传递参数,以及如何在 Step 中获取参数。

方式一:通过应用程序参数传递

创建 BatchConfig 配置

package com.hxstrive.spring_batch.jobParameterDemo.config;

import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;

/**
 * Spring Batch 配置类
 * @author hxstrive.com
 */
@Configuration
public class BatchConfig implements StepExecutionListener {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    private Map<String, JobParameter> jobParameters;


    // 创建JOB对象
    @Bean
    public Job jobParameterDemoJob() {
        return jobBuilderFactory.get("jobParameterDemoJob")
                .start(jobParameterDemoStep())
                .build();
    }

    @Bean
    public Step jobParameterDemoStep() {
        return stepBuilderFactory.get("jobParameterDemoStep")
                .listener(this)
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("JobParameters: " + jobParameters);
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        System.out.println("beforeStep");
        jobParameters = stepExecution.getJobParameters().getParameters();
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        System.out.println("afterStep");
        return null;
    }
}

上面代码实现了 StepExecutionListener  接口,StepExecutionListener  是一个 Step 执行时的监听器,分别在 Step 执行前后触发回调方法。我们将在 beforeStep(StepExecution stepExecution) 方法中,通过 StepExecution 获取 JobParameters 对象,并赋值给全局变量。然后,在 Step 中将 JobParameters 对象的值打印到控制台。

创建启动类

package com.hxstrive.spring_batch.jobParameterDemo;

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableBatchProcessing // 开启批处理
public class SpringBatchDemoApplication {

    public static void main(String[] args) {
       // 添加参数
       args = new String[] {"info=hello world", "debug=true"};
       SpringApplication.run(SpringBatchDemoApplication.class, args);
    }

}

在启动类中,通过 args 传递多个参数到应用程序。

运行项目,效果如下图:

image.png

image.png

从上图可以看见,已经成功将参数传递到 Step 中。

  

方式二:通过 JobLauncher 传递

JobLauncher 是负责启动和执行批处理作业的核心组件。它作为作业执行的入口点,提供了将 Job 定义与运行时参数相结合的机制。例如:

package com.hxstrive.spring_batch.jobLauncherDemo;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
@EnableBatchProcessing // 开启批处理
public class SpringBatchDemoApplication {

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private Job jobLauncherDemoJob; // 要启动的 JOB

    public static void main(String[] args) {
       SpringApplication.run(SpringBatchDemoApplication.class, args);
    }

    @GetMapping("/runJob")
    public void runJob(@RequestParam String message) throws Exception {
       // 传递参数到任务
       JobParameters jobParameters = new JobParametersBuilder()
             .addString("message", message).toJobParameters();
       // 执行任务
       jobLauncher.run(jobLauncherDemoJob, jobParameters);
    }

}

上述代码,将通过调用 /runJob 接口去启动一个 Job,并且将接口传递的 message 参数传递给 Job。

运行效果如下图:

image.png

image.png

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号