Skip to content

运行 Spring Batch 作业

本教程详细讲解 Spring Batch 作业的两种运行方式:命令行启动和 Web 容器启动。通过实际代码示例和最佳实践,帮助初学者掌握作业运行机制。


一、核心运行组件

最小启动要求

运行批处理作业需要两个核心组件:

  1. Job - 定义批处理逻辑
  2. JobLauncher - 作业启动器
    两者可部署在同一上下文或不同上下文中。

NOTE

部署模式差异

  • 命令行启动:每个作业在新 JVM 中运行,拥有独立的 JobLauncher
  • Web 容器启动:多个请求共享异步配置的 JobLauncher

二、命令行运行作业

企业级调度系统通常通过命令行触发作业,因其直接与操作系统进程交互。

1. CommandLineJobRunner

Spring Batch 提供的命令行入口类,主要功能:

必需参数:
参数说明
jobPath包含完整作业配置的 XML/Kotlin 文件路径
jobName要运行的作业名称
参数格式示例:
bash
java CommandLineJobRunner io.spring.EndOfDayJobConfig endOfDay \
    schedule.date=2023-12-01,java.time.LocalDate,true \
    vendor.id=456,java.lang.Long,false

参数标识说明

后缀 true/false 声明参数是否为标识参数:

  • schedule.date=...,true → 作业标识参数
  • vendor.id=...,false → 普通参数
Kotlin 作业配置示例:
kotlin
@Configuration
@EnableBatchProcessing
class EndOfDayJobConfig {

    @Bean
    fun endOfDayJob(jobRepository: JobRepository): Job {
        return JobBuilder("endOfDay", jobRepository)
            .start(step1())  
            .build()
    }

    @Bean
    fun step1(jobRepository: JobRepository,
              transactionManager: PlatformTransactionManager) =
        StepBuilder("step1", jobRepository)
            .tasklet({ _, _ -> null }, transactionManager)
            .build()
}

2. 退出码处理

调度系统通过退出码判断作业执行结果:

kotlin
// 自定义退出码映射器
class CustomExitMapper : ExitCodeMapper {
    override fun intValue(exitCode: String): Int {
        return when(exitCode) {
            "COMPLETED" -> 0
            "FAILED" -> 1
            "RESTART" -> 10  // 特殊代码需调度器支持
            else -> 2
        }
    }
}

注意事项

  1. 默认映射规则:
    • 0 = 成功
    • 1 = 通用错误
    • 2 = 作业启动错误
  2. 声明自定义映射器需注册为根级 Bean

三、Web 容器运行作业

适用于报表生成、即席作业等需要 HTTP 触发的场景,需异步启动避免阻塞请求。

异步启动流程:

Kotlin 控制器实现:

kotlin
@Controller
class JobLauncherController(
    @Autowired private val jobLauncher: JobLauncher,
    @Autowired private val endOfDayJob: Job
) {

    @GetMapping("/runJob")
    fun launchJob(): ResponseEntity<String> {
        val future = CompletableFuture.runAsync {
            jobLauncher.run(endOfDayJob, JobParameters())  
        }
        return ResponseEntity.accepted().body("作业已启动")
    }
}
kotlin
// 会阻塞HTTP线程
jobLauncher.run(job, JobParameters())
kotlin
// 使用TaskExecutor实现非阻塞
@Bean
fun asyncJobLauncher(jobRepository: JobRepository): JobLauncher {
    return TaskExecutorJobLauncher().apply {
        setJobRepository(jobRepository)
        setTaskExecutor(SimpleAsyncTaskExecutor())  
    }
}

四、关键配置说明

最佳实践

  1. Web 容器配置
kotlin
@Configuration
class BatchConfig {

    @Bean
    fun jobLauncher(jobRepository: JobRepository) =
        TaskExecutorJobLauncher().apply {
            setJobRepository(jobRepository)
            setTaskExecutor(ThreadPoolTaskExecutor().apply {
                corePoolSize = 5
                maxPoolSize = 10
            })
        }
}
  1. 作业参数安全注入
kotlin
@Bean
fun jobParamValidator() = JobParametersValidator { parameters ->
    if(!parameters.containsKey("run.date")) {
        throw JobParametersInvalidException("缺少run.date参数")  
    }
}

CAUTION

安全警告
开放 HTTP 作业触发端点时:

  • 添加身份验证 @PreAuthorize("hasRole('ADMIN')")
  • 验证参数合法性防止恶意注入
  • 限制并发启动次数

五、总结对比

启动方式适用场景优势注意事项
命令行启动定时任务/调度系统资源隔离,稳定性高需处理退出码映射
Web 容器异步启动用户触发/即席作业集成便捷,响应快速需防止资源耗尽

扩展知识

作业监听器:实现 JobExecutionListener 记录执行日志
参数增量器:使用 JobParametersIncrementer 自动生成运行ID
元数据管理:通过 JobExplorer 查询历史执行记录

通过本教程,您已掌握 Spring Batch 作业的核心启动机制,可根据实际需求选择最适合的运行方式。