乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 批处理概述与 Spring Batch 核心理念

    • Spring Batch 概述
    • Job-Instance-Execution 三层生命周期
    • 三层架构
    • Chunk 处理模型
    • Tasklet 处理模型
  • 第2章 Job与作业配置

    • Job 详解
    • Job 配置
    • JobLauncher 详解
    • JobParameters 详解
    • JobRepository 详解
  • 第3章 Step与执行模型

    • Step 详解
    • Step 配置
    • ExecutionContext 详解
    • ItemStream 与状态管理
    • StepScope 与 JobScope
  • 第4章 ItemReader数据读取

    • ItemReader 详解
    • FlatFileItemReader 详解
    • JdbcItemReader 详解
    • MultiResourceItemReader 详解
  • 第5章 ItemProcessor 数据处理

    • ItemProcessor 详解
  • 第6章 ItemWriter 数据写出

    • ItemWriter 详解
    • FlatFileItemWriter 详解
    • CompositeItemWriter 详解
    • JdbcBatchItemWriter 详解
  • 第7章 Chunk 处理与事务边界

    • Chunk 处理模型详解
    • 事务边界
  • 第8章 作业参数与启动

    • 命令行与 Web 启动
  • 第9章 监听器与拦截器

    • 监听器详解
  • 第10章 重启重试与跳过策略

    • 重启与重试
    • 跳过策略
  • 第11章 作业流与条件决策

    • 作业流与条件决策
  • 第12章 分区与并行处理

    • 分区详解
    • 并行 Step 与 Split
  • 第13章 与 Spring Boot 集成实践

    • Spring Boot 集成
  • 第15章 运维与监控

    • 大作业设计模式
    • 运维与监控

JobParameters 详解

本章定位:彻底理解 JobParameters 的设计意图——不仅是"启动参数",更是 JobInstance 的唯一性标识和延迟绑定的数据源。

定义与作用

JobParameters 是启动 Job 时传入的键值对参数集合,具有双重作用:

  1. 标识 JobInstance:同一 Job + 同一组 JobParameters → 同一个 JobInstance
  2. 传递运行时数据:如文件路径、处理日期、批次号等

飞翔科技架构师白歌强调:

"JobParameters 和普通方法参数最大的不同在于:它是不可变的、被持久化到元数据表的、参与 JobInstance 标识的。你今天用 date=2026-06-13 跑一遍,明天用相同的参数再跑就会报错——因为 Spring Batch 认为这是同一个 JobInstance。"

核心原理

JobParameters 的生命周期

参数类型与识别

JobParameters 支持四种类型,通过 identifying 标志区分:

参数类型方法identifying 默认值说明
StringaddString(key, value)true最常用,如文件路径、日期字符串
LongaddLong(key, value)true如 run.id、时间戳
DoubleaddDouble(key, value)true如金额阈值
DateaddDate(key, value)true如处理截止日期

Identifying vs Non-Identifying:

  • Identifying 参数(默认):参与 JobInstance 识别。参数变了 → 新的 JobInstance
  • Non-Identifying 参数:不参与识别。参数变了仍然复用同一个 JobInstance
// 两种参数混合使用
JobParameters params = new JobParametersBuilder()
        .addString("input.file", "students.csv")              // identifying(默认)
        .addLong("run.id", 1L)                                // identifying
        .addString("email.to", "ops@feixiang.net", false)     // non-identifying
        .addLong("batch.size", 500L, false)                   // non-identifying
        .toJobParameters();

完整示例

场景一:飞翔科技——按日期处理订单文件

背景:运营部杨英每天收到格式为 orders_YYYYMMDD.csv 的订单文件,需要用 Spring Batch 处理。

@RestController
public class OrderJobController {

    private final JobLauncher jobLauncher;
    private final Job orderJob;

    public OrderJobController(JobLauncher jobLauncher, Job orderJob) {
        this.jobLauncher = jobLauncher;
        this.orderJob = orderJob;
    }

    @PostMapping("/jobs/orders")
    public String runOrderJob(@RequestParam String date) throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addString("orderDate", date)                        // 如 "2026-06-13"
                .addString("input.file", "orders_" + date + ".csv")  // 动态文件路径
                .addLong("run.id", System.currentTimeMillis())       // 确保唯一性
                .toJobParameters();

        JobExecution execution = jobLauncher.run(orderJob, params);
        return "Job started: " + execution.getJobId();
    }
}

操作前后对比:

POST /jobs/orders?date=2026-06-13
→ JobParameters: {orderDate=2026-06-13, input.file=orders_20260613.csv, run.id=1718265600000}
→ JobInstance #1, JobExecution #1 → 正常执行

POST /jobs/orders?date=2026-06-13  (重复请求)
→ JobParameters: {orderDate=2026-06-13, input.file=orders_20260613.csv, run.id=1718265600001}
→ JobInstance #2  ← run.id 不同,所以是新实例!

POST /jobs/orders?date=2026-06-14
→ JobParameters: {orderDate=2026-06-14, input.file=orders_20260614.csv, run.id=1718352000000}
→ JobInstance #3  ← orderDate 也不同了

场景二:延迟绑定——在 Reader 中使用 JobParameters

@StepScope + @Value 是访问 JobParameters 最常用的方式:

@Bean
@StepScope
public FlatFileItemReader<Order> orderReader(
        @Value("#{jobParameters['input.file']}") String inputFile) {
    return new FlatFileItemReaderBuilder<Order>()
            .name("orderReader")
            .resource(new FileSystemResource(inputFile))  // 运行时才确定文件路径
            .delimited().delimiter(",")
            .names("orderId", "customerName", "amount", "orderDate")
            .targetType(Order.class)
            .linesToSkip(1)
            .build();
}

关键:@StepScope 确保 Bean 在 Step 启动时才实例化,此时 JobParameters 已经可用。如果不加 @StepScope,Spring 在容器初始化时就尝试解析 #{jobParameters[...]},此时参数还未传入。

易错场景与避坑

反例一:忘记加 @StepScope 导致启动报错

// ❌ 没有 @StepScope → Spring 初始化时就尝试解析 SpEL → 报错
@Bean
public FlatFileItemReader<Order> reader(
        @Value("#{jobParameters['input.file']}") String inputFile) {
    // ...
}
// 错误:EL1007E: Property or field 'input' cannot be found on null

正确做法:必须加 @StepScope。

反例二:Non-Identifying 参数误解

小崔以为只要参数标记为 non-identifying 就不会影响 JobInstance,但实际行为更微妙:

// 第一次执行
JobParameters params1 = new JobParametersBuilder()
        .addString("date", "2026-06-13")
        .addLong("batch.size", 100L, false)  // non-identifying
        .toJobParameters();
jobLauncher.run(job, params1);  // → JobInstance #1,COMPLETED

// 第二次执行——只改了 non-identifying 参数
JobParameters params2 = new JobParametersBuilder()
        .addString("date", "2026-06-13")     // 相同
        .addLong("batch.size", 500L, false)  // 不同,但 non-identifying
        .toJobParameters();
jobLauncher.run(job, params2);
// → JobInstanceAlreadyCompleteException!
// 因为 identifying 参数相同 → 同一个 JobInstance → 已 COMPLETED

正确理解:Non-identifying 参数不参与 JobInstance 识别,但也不足以区分不同的 JobInstance。需要 identifying 参数变化才能创建新的 JobInstance。

面试高频考点

Q1:JobParameters 和 ExecutionContext 有什么区别?

JobParameters 是启动时传入的不可变参数,用于标识 JobInstance。ExecutionContext 是运行时的可读写状态存储,用于断点续传和步骤间数据传递。前者是"输入",后者是"中间状态"。

Q2:Identifying 和 Non-Identifying 参数的区别?

Identifying 参数参与 JobInstance 的唯一性识别(默认行为),Non-Identifying 参数不参与。如果两次执行的 Identifying 参数完全相同 → 同一个 JobInstance。Non-Identifying 参数通常用于传递不影响实例唯一性的配置值(如邮件接收人、批处理大小)。

Q3:如何保证每次启动都创建新的 JobInstance?

三种方式:① 使用 RunIdIncrementer(最推荐);② 在参数中加入时间戳 System.currentTimeMillis();③ 在参数中加入业务唯一标识(如日期 + 序列号)。


上一章:Job 配置下一章:JobLauncher 详解

上一页
JobLauncher 详解
下一页
JobRepository 详解