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

    • 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章 运维与监控

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

命令行与 Web 启动

本章定位:掌握 Spring Batch Job 的三种启动方式——CommandLineRunner、REST API 和定时调度,以及生产环境的启动最佳实践。

定义与作用

Spring Batch Job 定义好后,需要通过某种方式触发执行。常见的三种触发方式对应不同的使用场景。

飞翔科技后端开发小崔的总结:

"命令行适合运维手动触发和 Cron 脚本,REST API 适合管理后台点击触发,@Scheduled 适合无人值守的定时任务。但不管哪种方式,最终都调用 jobLauncher.run(job, params)。"

核心原理

三种方式对比

方式适用场景优点缺点
命令行运维脚本、一次性任务简单直接,不依赖 Web 容器需要服务器权限
REST API管理后台、手动触发灵活,可集成到任何前端需要 Web 容器
@Scheduled定时批处理无人值守,自动运行不支持集群(需额外处理)

完整示例

场景一:命令行启动

@SpringBootApplication
public class BatchApplication implements CommandLineRunner {

    private final JobLauncher jobLauncher;
    private final Job orderJob;

    public BatchApplication(JobLauncher jobLauncher,
                            @Qualifier("orderProcessingJob") Job orderJob) {
        this.jobLauncher = jobLauncher;
        this.orderJob = orderJob;
    }

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

    @Override
    public void run(String... args) throws Exception {
        // 读取命令行参数
        String date = args.length > 0 ? args[0] : LocalDate.now().toString();

        JobParameters params = new JobParametersBuilder()
                .addString("orderDate", date)
                .addLong("run.id", System.currentTimeMillis())
                .toJobParameters();

        JobExecution execution = jobLauncher.run(orderJob, params);
        System.out.println("Exit Status: " + execution.getExitStatus().getExitCode());
    }
}
# 命令行执行
java -jar feixiang-batch.jar 2026-06-13
# Exit Status: COMPLETED

场景二:REST API 触发(异步)

@RestController
@RequestMapping("/api/batch")
public class AsyncBatchController {

    private final JobLauncher asyncJobLauncher;
    private final Job orderJob;

    public AsyncBatchController(
            @Qualifier("asyncJobLauncher") JobLauncher asyncJobLauncher,
            @Qualifier("orderProcessingJob") Job orderJob) {
        this.asyncJobLauncher = asyncJobLauncher;
        this.orderJob = orderJob;
    }

    @PostMapping("/orders/run")
    public ResponseEntity<Map<String, Object>> runOrderJob(
            @RequestParam String date) throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addString("orderDate", date)
                .addLong("triggeredAt", System.currentTimeMillis())
                .toJobParameters();

        // 异步启动:立即返回 executionId
        JobExecution execution = asyncJobLauncher.run(orderJob, params);
        return ResponseEntity.accepted().body(Map.of(
            "executionId", execution.getId(),
            "status", "STARTED",
            "checkUrl", "/api/batch/orders/status/" + execution.getId()
        ));
    }

    @GetMapping("/orders/status/{id}")
    public ResponseEntity<Map<String, Object>> getStatus(
            @PathVariable Long id, JobExplorer explorer) {
        JobExecution exec = explorer.getJobExecution(id);
        return ResponseEntity.ok(Map.of(
            "executionId", exec.getId(),
            "status", exec.getStatus().name(),
            "startTime", exec.getStartTime(),
            "endTime", exec.getEndTime()
        ));
    }
}

场景三:定时调度 + 防止 Spring Boot 自动启动

# application.properties
spring.batch.job.enabled=false   # 禁止 Spring Boot 启动时自动执行所有 Job
@Component
public class ScheduledBatchJobs {

    private final JobLauncher jobLauncher;
    private final Job reportJob;

    public ScheduledBatchJobs(JobLauncher jobLauncher,
                              @Qualifier("nightlyReportJob") Job reportJob) {
        this.jobLauncher = jobLauncher;
        this.reportJob = reportJob;
    }

    @Scheduled(cron = "0 0 2 * * ?")  // 每天凌晨 2:00
    public void runNightlyReport() throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addString("reportDate", LocalDate.now().toString())
                .addLong("run.id", System.currentTimeMillis())
                .toJobParameters();
        jobLauncher.run(reportJob, params);
    }
}

易错场景与避坑

反例一:忘记设置 spring.batch.job.enabled=false

# ❌ 没有这个配置 → Spring Boot 启动时自动执行所有 Job
# spring.batch.job.enabled 默认为 true

后果:应用启动时就跑批处理,导致启动极慢。如果应用是 Web 服务,用户请求会被阻塞。

反例二:同步 Web 请求 + 长时间 Job

// ❌ 同步 JobLauncher + HTTP 请求 → 请求超时
JobExecution exec = syncJobLauncher.run(longJob, params); // 跑 30 分钟
// HTTP 请求 30 秒就超时了

正确做法:Web 触发必须使用异步 JobLauncher。

面试高频考点

Q1:spring.batch.job.enabled=false 的作用?

禁止 Spring Boot 在启动时自动执行所有已注册的 Job Bean。在 Web 应用中必须设置为 false,否则应用启动时会自动跑批处理。

Q2:如何实现集群环境下的定时 Job 去重?

@Scheduled 在每个实例上都执行,会导致重复。解决方案:①使用分布式锁(Redis/ZK);②使用 Spring Cloud Data Flow 的调度器;③外部 Cron + 单实例执行脚本。


上一章:Chunk 处理模型详解下一章:监听器详解