You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot启动时自动执行Spring Batch Job的配置咨询

Spring Boot 3 + Spring Batch 启动后Job未执行的解决配置方案

问题描述

基于Java 17、Spring Boot 3.0.0开发的Spring Batch应用,启动后Job未自动运行,需配置实现启动时执行一次Job,完成后自动结束应用。

现有配置信息

1. Gradle依赖配置

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-batch")
    implementation("org.springframework.boot:spring-boot-starter-data-elasticsearch")
    implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
    runtimeOnly("com.oracle.database.jdbc:ojdbc8")
    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
    runtimeOnly("io.micrometer:micrometer-registry-prometheus")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework.batch:spring-batch-test")
}

2. Batch配置类

@Configuration
@EnableBatchProcessing
@EnableElasticsearchRepositories
public class PhqBatchConfiguration {

    private static final Logger log = LoggerFactory.getLogger(PhqBatchConfiguration.class);
    private DataSource dataSource;

    @Autowired
    public PhqBatchConfiguration(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public PhqRangePartitioner partitioner(){
        return new PhqRangePartitioner(dataSource, 1000);
    }

    //Master
    @Bean(name = "partitionStep")
    public Step partitionStep(JobRepository jobRepository,
                              PhqRangePartitioner phqRangePartitioner){
        log.info("### creating partition step");
        return new StepBuilder("partitionStep", jobRepository)
                .partitioner("partitionStep",phqRangePartitioner)
                .build();
    }


    @Bean
    public Job partitionJob(JobRepository jobRepository, @Qualifier("partitionStep") Step partitionStep){
        log.info("### creating partition Job");
        return new JobBuilder("partitionJob", jobRepository).start(partitionStep).build();
    }

    @Bean(name = "phqReader")
    @StepScope
    public JdbcCursorItemReader<Phq> pagingItemReader(
            @Value("#{stepExecutionContext['ROWNUM_START']}")int rownumStart,
            @Value("#{stepExecutionContext['ROWNUM_END']}")int rownumEnd,
            @Value("#{stepExecutionContext['PARTITION_NAME']}")String partitionName){

        log.info("### creating paging item reader");
        PhqItemReader phqItemReader = new PhqItemReader(dataSource, partitionName,rownumStart,rownumEnd);
        return phqItemReader;
    }

    @Bean(name="importPhqStep")
    public Step importPhqStep(JobRepository jobRepository,
                              PlatformTransactionManager transactionManager,
                              @Qualifier("phqReader") JdbcCursorItemReader<Phq> phqItemReader,
                              ItemWriter<Phq> phqItemWriter){
        log.info("### creating import Phq step");
        return new StepBuilder("importStep", jobRepository)
                .<Phq,Phq>chunk(1000, transactionManager)
                .reader(phqItemReader)
                .writer(phqItemWriter)
                .build();
    }
}

3. 应用启动日志

.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\
( ( )\___ | '_ | '_| | '_ \/ _` | \\ \\ \\ \\
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::                (v3.0.0)

2022-12-30T16:55:43.643+01:00  INFO 57061 --- [           main] c.c.p.c.e.ElasticImporterApplication     : Starting ElasticImporterApplication using Java 17.0.5 with PID 57061 (/Users/ramseshughanta/workspace/cswg_ws/elastic-importer/build/classes/java/main started by ramseshughanta in /Users/ramseshughanta/workspace/cswg_ws/elastic-importer)
2022-12-30T16:55:43.644+01:00  INFO 57061 --- [           main] c.c.p.c.e.ElasticImporterApplication     : No active profile set, falling back to 1 default profile: "default"
2022-12-30T16:55:43.773+01:00  INFO 57061 --- [           main] o.s.b.c.c.annotation.BatchRegistrar      : Finished Spring Batch infrastructure beans configuration in 2 ms.
2022-12-30T16:55:43.777+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2022-12-30T16:55:43.777+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode.
2022-12-30T16:55:43.780+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 1 ms. Found 0 Elasticsearch repository interfaces.
2022-12-30T16:55:43.856+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2022-12-30T16:55:43.856+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode.
2022-12-30T16:55:43.860+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 4 ms. Found 0 Elasticsearch repository interfaces.
2022-12-30T16:55:43.861+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2022-12-30T16:55:43.862+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode.
2022-12-30T16:55:43.863+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 0 ms. Found 0 Reactive Elasticsearch repository interfaces.
2022-12-30T16:55:43.870+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2022-12-30T16:55:43.870+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
2022-12-30T16:55:43.871+01:00  INFO 57061 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 0 ms. Found 0 JDBC repository interfaces.
2022-12-30T16:55:43.954+01:00  INFO 57061 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-12-30T16:55:46.349+01:00  INFO 57061 --- [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection oracle.jdbc.driver.T4CConnection@1e253c9d
2022-12-30T16:55:46.351+01:00  INFO 57061 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2022-12-30T16:55:46.359+01:00  INFO 57061 --- [           main] o.s.b.c.r.s.JobRepositoryFactoryBean     : No database type set, using meta data indicating: ORACLE
2022-12-30T16:55:46.370+01:00  INFO 57061 --- [           main] c.c.p.c.e.config.PhqBatchConfiguration   : ### creating partition step
2022-12-30T16:55:46.381+01:00  INFO 57061 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2022-12-30T16:55:46.382+01:00  INFO 57061 --- [           main] c.c.p.c.e.config.PhqBatchConfiguration   : ### creating partition Job
2022-12-30T16:55:46.384+01:00  INFO 57061 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2022-12-30T16:55:46.385+01:00  INFO 57061 --- [           main] c.c.p.c.e.config.PhqBatchConfiguration   : ### creating import Phq step
2022-12-30T16:55:46.395+01:00  INFO 57061 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2022-12-30T16:55:46.396+01:00  INFO 57061 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : No TaskExecutor has been set, defaulting to synchronous executor.
2022-12-30T16:55:46.640+01:00  INFO 57061 --- [           main] c.c.p.c.e.ElasticImporterApplication     : Started ElasticImporterApplication in 3.118 seconds (process running for 3.322)
2022-12-30T16:55:56.244+01:00  INFO 57061 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...

Process finished with exit code 137 (interrupted by signal 9: SIGKILL)

问题分析

  1. Spring Boot默认不自动启动Job:日志显示Job和Step的Bean已成功创建,但没有触发执行逻辑,因为Spring Boot默认不会自动运行定义的Batch Job。
  2. 分区Step配置不完整:当前的partitionStep仅指定了分区器,但未关联实际执行数据处理的importPhqStep,导致分区Step无法调度具体的任务逻辑。

解决步骤

1. 配置自动启动Job

在application.properties或application.yml中添加以下配置,让Spring Boot启动时自动执行Job:

# 执行所有定义的Job
spring.batch.job.enabled=true
# 仅执行指定名称的Job(二选一)
# spring.batch.job.names=partitionJob

2. 修复分区Step配置

修改partitionStep的Bean定义,关联实际处理的worker step(importPhqStep),同时可配置任务执行器实现异步分区:

@Bean(name = "partitionStep")
public Step partitionStep(JobRepository jobRepository,
                          PhqRangePartitioner phqRangePartitioner,
                          @Qualifier("importPhqStep") Step importPhqStep,
                          PlatformTransactionManager transactionManager){
    log.info("### creating partition step");
    return new StepBuilder("partitionStep", jobRepository)
            .partitioner("importPhqStep", phqRangePartitioner) // 指定worker step的名称
            .step(importPhqStep) // 关联实际执行的worker step
            .transactionManager(transactionManager)
            .taskExecutor(new SimpleAsyncTaskExecutor()) // 可选,异步执行分区任务,提升处理效率
            .build();
}

3. 配置Job完成后自动关闭应用

Spring Boot默认会保持容器运行,需配置在Job执行完成后自动关闭应用:

  • 方式一:使用Spring Boot配置(Spring Boot 3+支持)
    spring.batch.job.close.context=true
    
  • 方式二:自定义启动器触发Job并关闭上下文
    实现ApplicationRunner手动触发Job,完成后关闭应用:
    @Component
    public class JobStartupRunner implements ApplicationRunner {
    
        private final JobLauncher jobLauncher;
        private final Job partitionJob;
        private final ApplicationContext applicationContext;
    
        public JobStartupRunner(JobLauncher jobLauncher, Job partitionJob, ApplicationContext applicationContext) {
            this.jobLauncher = jobLauncher;
            this.partitionJob = partitionJob;
            this.applicationContext = applicationContext;
        }
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            JobExecution jobExecution = jobLauncher.run(partitionJob, new JobParameters());
            if (BatchStatus.COMPLETED.equals(jobExecution.getStatus())) {
                SpringApplication.exit(applicationContext, () -> 0);
            }
        }
    }
    

内容的提问来源于stack exchange,提问作者Ram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:00:59