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)
问题分析
- Spring Boot默认不自动启动Job:日志显示Job和Step的Bean已成功创建,但没有触发执行逻辑,因为Spring Boot默认不会自动运行定义的Batch Job。
- 分区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
相关产品推荐
相关产品推荐

