在 Spring Batch 中,嵌套 Job(Nested Job) 是指将一个或多个独立的 Job 作为另一个父 Job 的步骤(Step)来执行的架构模式。核心是通过 JobStep 组件实现 Job 的层级调用,形成父子执行关系。如下图:
上图执行流程如下:父 Job 按顺序执行 Steps(常规 Step → JobStep → 常规 Step),如果遇到 JobStep 时,触发子 Job 的完整执行周期(包括其所有 Steps,即子Job1、子Job2)。注意:子 Job 执行状态(成功/失败)决定父 Job 后续流程。
在 Spring Batch 中,JobStepBuilder 是一个关键的构建器类,用于创建一种特殊的步骤(Step)—— 作业步骤(JobStep)。作业步骤允许在一个作业中嵌套执行另一个独立的作业,从而实现复杂的批处理编排。
JobStepBuilder 是 StepBuilder 的扩展,专门用于构建作业步骤。其核心方法包括:
job(Job job):指定要嵌套执行的作业。
launcher(JobLauncher jobLauncher):指定作业启动器(可选,默认使用父作业的启动器)。
parametersExtractor(JobParametersExtractor extractor):从父作业传递参数到子作业。
on(String exitStatus):定义子作业执行后的路由规则(类似普通步骤)。
当前示例将展示“作业嵌套(Job Nesting)”的基本用法,创建一个 parentJob,该 Job 下面有两个子 Job(childJob1 和 childJob2),如下图:
要实现该示例,具体步骤如下:
(1)修改 application.properties 配置,添加如下内容:
spring.batch.job.names=parentJob
上述配置通过 spring.batch.job.names 指定了应用启动时自动执行的 Job 名称。当您设置这个属性时,应用会在启动后立即运行名为 parentJob 的批处理作业。
(2)创建 BatchConfig 配置类,代码如下:
package com.hxstrive.spring_batch.jobNestedDemo.config; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.builder.JobStepBuilder; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.core.step.tasklet.Tasklet; 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 org.springframework.transaction.PlatformTransactionManager; /** * Spring Batch 配置类 * @author hxstrive.com */ @Configuration public class BatchConfig { // 用于创建和配置 Job 对象的工厂类 @Autowired private JobBuilderFactory jobBuilderFactory; // 用于创建和配置 Step 对象的工厂类 @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private JobLauncher launcher; // 创建 Step 对象 @Bean public Step jobNestedDemoStep1() { return stepBuilderFactory.get("jobNestedDemoStep1").tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception { System.out.println(Thread.currentThread().getName() + " jobNestedDemoStep1"); return RepeatStatus.FINISHED; // 返回 FINISHED 表明任务执行结束 } }).build(); } @Bean public Step jobNestedDemoStep2() { return stepBuilderFactory.get("jobNestedDemoStep2").tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception { System.out.println(Thread.currentThread().getName() + " jobNestedDemoStep2"); return RepeatStatus.FINISHED; // 返回 FINISHED 表明任务执行结束 } }).build(); } @Bean public Step jobNestedDemoStep3() { return stepBuilderFactory.get("jobNestedDemoStep3").tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception { System.out.println(Thread.currentThread().getName() + " jobNestedDemoStep3"); return RepeatStatus.FINISHED; // 返回 FINISHED 表明任务执行结束 } }).build(); } // 创建 Job 对象 // Job 类型的 Step,特殊的 Step @Bean public Job jobNestedDemoJob1() { return jobBuilderFactory.get("jobNestedDemoJob1") .start(jobNestedDemoStep1()) .next(jobNestedDemoStep2()) .build(); } @Bean public Job jobNestedDemoJob2() { return jobBuilderFactory.get("jobNestedDemoJob2") .start(jobNestedDemoStep3()) .build(); } // 创建子JOB对象,通过 JobStepBuilder 将子作业转换为父作业中的一个步骤 @Bean public Step childJob1(JobRepository jobRepository, PlatformTransactionManager transactionManager) { return new JobStepBuilder(new StepBuilder("childJob1")) .job(jobNestedDemoJob1()) // 指定要嵌套的子作业 .launcher(launcher) // 指定作业启动器 .repository(jobRepository) // 指定作业仓库 .transactionManager(transactionManager) // 指定事务管理器 .build(); } @Bean public Step childJob2(JobRepository jobRepository, PlatformTransactionManager transactionManager) { return new JobStepBuilder(new StepBuilder("childJob2")) .job(jobNestedDemoJob2()) // 指定要嵌套的子作业 .launcher(launcher) // 指定作业启动器 .repository(jobRepository) // 指定作业仓库 .transactionManager(transactionManager) // 指定事务管理器 .build(); } // 创建 Job 任务 // 需要配置 // spring.batch.job.names=parentJob @Bean public Job parentJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) { return jobBuilderFactory.get("parentJob") .start(childJob1(jobRepository, transactionManager)) .next(childJob2(jobRepository, transactionManager)) .build(); } }
上述代码中,parentJob() 的执行流程为,先执行 childJob1(内部运行 jobNestedDemoJob1),若 childJob1 成功完成,执行 childJob2(内部运行 jobNestedDemoJob2)。