Skip to content

Migrate to Spring Batch 6 #46216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.configuration.support.JdbcDefaultBatchConfiguration;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.ObjectProvider;
Expand Down Expand Up @@ -71,7 +71,7 @@
* @since 1.0.0
*/
@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TransactionAutoConfiguration.class })
@ConditionalOnClass({ JobLauncher.class, DataSource.class, DatabasePopulator.class })
@ConditionalOnClass({ JobOperator.class, DataSource.class, DatabasePopulator.class })
@ConditionalOnBean({ DataSource.class, PlatformTransactionManager.class })
@ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class)
@EnableConfigurationProperties(BatchProperties.class)
Expand All @@ -81,9 +81,9 @@ public class BatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBooleanProperty(name = "spring.batch.job.enabled", matchIfMissing = true)
public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer,
public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobOperator jobOperator,
JobRepository jobRepository, BatchProperties properties) {
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository);
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobOperator, jobRepository);
String jobName = properties.getJob().getName();
if (StringUtils.hasText(jobName)) {
runner.setJobName(jobName);
Expand All @@ -98,7 +98,7 @@ public JobExecutionExitCodeGenerator jobExecutionExitCodeGenerator() {
}

@Configuration(proxyBeanMethods = false)
static class SpringBootBatchConfiguration extends DefaultBatchConfiguration {
static class SpringBootBatchConfiguration extends JdbcDefaultBatchConfiguration {

private final DataSource dataSource;

Expand Down Expand Up @@ -172,6 +172,7 @@ protected ExecutionContextSerializer getExecutionContextSerializer() {
: super.getExecutionContextSerializer();
}

@SuppressWarnings("removal")
Copy link
Member

@snicoll snicoll Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what to make of this. The method is deprecated but the class isn't. If we don't want this to be configurable going forward, I'd rather remove the override (and the ObjectProvider)

@Override
protected JobParametersConverter getJobParametersConverter() {
return (this.jobParametersConverter != null) ? this.jobParametersConverter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

package org.springframework.boot.autoconfigure.batch;

import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.configuration.support.JdbcDefaultBatchConfiguration;
import org.springframework.core.convert.support.ConfigurableConversionService;

/**
* Callback interface that can be implemented by beans wishing to customize the
* {@link ConfigurableConversionService} that is
* {@link DefaultBatchConfiguration#getConversionService provided by
* {@link JdbcDefaultBatchConfiguration#getConversionService provided by
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should relax the javadoc a bit. It looks weird that we refer to that method. Something like

Callback interface that can be implemented by beans wishing to customize the ConfigurableConversionService that is use by the batch infrastructure while retaining its default auto-configuration.

* DefaultBatchConfiguration} while retaining its default auto-configuration.
*
* @author Claudio Nave
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package org.springframework.boot.autoconfigure.batch;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.job.JobExecution;
import org.springframework.context.ApplicationEvent;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.job.JobExecution;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.context.ApplicationListener;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@
import org.apache.commons.logging.LogFactory;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.job.Job;
import org.springframework.batch.core.job.JobExecution;
import org.springframework.batch.core.job.JobExecutionException;
import org.springframework.batch.core.job.parameters.JobParameter;
import org.springframework.batch.core.job.parameters.JobParameters;
import org.springframework.batch.core.job.parameters.JobParametersBuilder;
import org.springframework.batch.core.job.parameters.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
Expand All @@ -55,7 +55,7 @@
import org.springframework.util.StringUtils;

/**
* {@link ApplicationRunner} to {@link JobLauncher launch} Spring Batch jobs. If a single
* {@link ApplicationRunner} to {@link JobOperator launch} Spring Batch jobs. If a single
* job is found in the context, it will be executed by default. If multiple jobs are
* found, launch a specific job by providing a jobName.
*
Expand All @@ -78,9 +78,7 @@ public class JobLauncherApplicationRunner

private JobParametersConverter converter = new DefaultJobParametersConverter();

private final JobLauncher jobLauncher;

private final JobExplorer jobExplorer;
private final JobOperator jobOperator;

private final JobRepository jobRepository;

Expand All @@ -96,17 +94,14 @@ public class JobLauncherApplicationRunner

/**
* Create a new {@link JobLauncherApplicationRunner}.
* @param jobLauncher to launch jobs
* @param jobExplorer to check the job repository for previous executions
* @param jobOperator to launch jobs
* @param jobRepository to check if a job instance exists with the given parameters
* when running a job
*/
public JobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, JobRepository jobRepository) {
Assert.notNull(jobLauncher, "'jobLauncher' must not be null");
Assert.notNull(jobExplorer, "'jobExplorer' must not be null");
public JobLauncherApplicationRunner(JobOperator jobOperator, JobRepository jobRepository) {
Assert.notNull(jobOperator, "'jobOperator' must not be null");
Assert.notNull(jobRepository, "'jobRepository' must not be null");
this.jobLauncher = jobLauncher;
this.jobExplorer = jobExplorer;
this.jobOperator = jobOperator;
this.jobRepository = jobRepository;
}

Expand Down Expand Up @@ -204,28 +199,31 @@ private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecut
}
}

protected void execute(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException,
JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
protected void execute(Job job, JobParameters jobParameters)
throws JobExecutionAlreadyRunningException, NoSuchJobException, JobRestartException,
JobInstanceAlreadyCompleteException, JobParametersInvalidException {
JobParameters parameters = getNextJobParameters(job, jobParameters);
JobExecution execution = this.jobLauncher.run(job, parameters);
JobExecution execution = this.jobOperator.start(job, parameters);
if (this.publisher != null) {
this.publisher.publishEvent(new JobExecutionEvent(execution));
}
}

@SuppressWarnings("deprecated")
private JobParameters getNextJobParameters(Job job, JobParameters jobParameters) {
if (this.jobRepository != null && this.jobRepository.isJobInstanceExists(job.getName(), jobParameters)) {
if (this.jobRepository != null && this.jobRepository.getJobInstance(job.getName(), jobParameters) != null) {
Copy link
Member

@snicoll snicoll Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something should be adapted in Spring Batch here. JobRepository isn't deprecated but JobExplorer is. The former extends the latter so any method that is not specified in the child is flagged as deprecated.

return getNextJobParametersForExisting(job, jobParameters);
}
if (job.getJobParametersIncrementer() == null) {
return jobParameters;
}
JobParameters nextParameters = new JobParametersBuilder(jobParameters, this.jobExplorer)
JobParameters nextParameters = new JobParametersBuilder(jobParameters, this.jobRepository)
.getNextJobParameters(job)
.toJobParameters();
return merge(nextParameters, jobParameters);
}

@SuppressWarnings("deprecated")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I see what this suppresses.

private JobParameters getNextJobParametersForExisting(Job job, JobParameters jobParameters) {
JobExecution lastExecution = this.jobRepository.getLastJobExecution(job.getName(), jobParameters);
if (isStoppedOrFailed(lastExecution) && job.isRestartable()) {
Expand Down
Loading
Loading