-
Couldn't load subscription status.
- Fork 2.4k
Spring Batch 6.0 Migration Guide
❗ This document is still in progress. We will update it regularly for each milestone version until the GA is released ❗
This document is meant to help you migrate your applications to Spring Batch 6.0. Spring Batch 6 does not change the minimum required Java version which remains Java 17+.
❗ Heads-up: While we tried to carefully list all changes here, we might have missed an API. If that is the case, then please open an issue by reporting the missing information and we will update this migration guide accordingly.
Spring Batch 6 upgrades its Spring dependencies to the following versions:
- Spring Framework 7
- Spring Integration 7
- Spring Data 4
- Spring AMQP 4
- Spring for Apache Kafka 4
- Micrometer 1.16
The Batch domain model was redesigned towards immutability. This had the following consequences in terms of API changes:
- It is not possible to re-assign an ID to any class extending
org.springframework.batch.core.Entity(ieJobInstance,JobExecution, etc) - Entity IDs have been changed from the wrapper
Longtype to the primitivelongtype. This is to avoid nullability issues in theJobRepositoryandJobOperatorAPIs - It is not possible to create orphan entities anymore (ie a job execution without a parent job instance, or a step execution without a parent job execution)
- It is not possible to query for "shallow" entities anymore (as in v5). Querying the job repository for an entity will return the entity and its siblings. We do not recommend keeping references to many job instances in memory, and a careful retention policy is now required on the client side. This issue is a no problem when following the best practice of running a single job in its own JVM.
- It is not possible to create batch artefacts (item readers, writers, etc) with default constructors + setters +
afterPropertiesSetcall. Required dependencies must now be specified at construction time. -
JobParameteris now a record (immutable by design/construction) and encapsulates the parameter name (which was previously the key of theMap<String, JobParameter>that backs theJobParametersclass)
Before v6, the @EnableBatchProcessing annotation was tied to a JDBC-based infrastructure. This is not the case anymore. Two new annotations have been introduced to configure the underlying job repository: @EnableJdbcJobRepository and EnableMongoJobRepository.
Starting from v6, @EnableBatchProcessing allows you to configure common attributes for the batch infrastructure, while store-specific attributes can be specified with the new dedicated annotations. Here is an example to migrate a JDBC configuration from v5 to v6:
// v5
@EnableBatchProcessing(dataSourceRef = "batchDataSource", taskExecutorRef = "batchTaskExecutor")
class MyJobConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// job flow omitted
.build();
}
}// v6
@EnableBatchProcessing(taskExecutorRef = "batchTaskExecutor")
@EnableJdbcJobRepository(dataSourceRef = "batchDataSource")
class MyJobConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// job flow omitted
.build();
}
}Similar to the annotation-based approach, the programmatic model based on DefaultBatchConfiguration has been updated by introducing two new configuration classes to define store-specific attributes: JdbcDefaultBatchConfiguration and MongoDefaultBatchConfiguration.
Here is an example to migrate a JDBC configuration from v5 to v6:
// v5
class MyJobConfiguration extends DefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// job flow omitted
.build();
}
@Override
protected DataSource getDataSource() {
return new MyBatchDataSource();
}
}// v6
class MyJobConfiguration extends JdbcDefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// job flow omitted
.build();
}
@Override
protected DataSource getDataSource() {
return new MyBatchDataSource();
}
}- The
DefaultBatchConfigurationnow configures a "resourceless" batch infrastructure (ie aResourcelessJobRepositoryand aResourcelessTransactionManager). This is to remove the need for an additional dependency to an in-memory database for those who do not need batch meta-data. - The configuration of a
JobExplorerbean has been removed. This is due to the fact thatJobRepositorynow extendsJobExplorerand there is no need for aJobExplorerbean anymore, which is now deprecated (See "Deprecated APIs" section). - The configuration of a
JobLauncherhas been replaced with aJobOperator. This is due to the fact thatJobOperatornow extendsJobLauncherand there is no need for aJobLauncherbean anymore, which is now deprecated (See "Deprecated APIs" section). - The configuration of a
JobRegistrySmartInitializingSingletonbean has been removed. TheMapJobRegistryis now optional as well , and is smart enough to populate itself with jobs from the application context on startup.JobRegistrySmartInitializingSingletonis now deprecated (See "Deprecated APIs" section). - The configuration of a transaction manager in
JobOperatorFactoryBeanis now optional - The configuration of a transaction manager in tasklet and chunk-oriented steps is now optional
The new implementation can be used by changing the following method call:
// legacy implementation (v5)
Step step = new StepBuilder("myStep", jobRepository)
.chunk(5, transactionManager)
// ...
.build();
// new implementation (v6)
Step step = new StepBuilder("myStep", jobRepository)
.chunk(5)
.transactionManager(transactionManager)
// ...
.build();
The legacy implementation will be available in a deprecated form for the entire v6 generation to give our users time to upgrade, but it will not be evolved or maintained in any way. Please consider moving to the new implementation in a timely manner during the lifetime of v6.
Before v6, the name of a job parameter lived outside the JobParameter class. It was used as a key of the internal map of JobParameters while it should be part of the JobParameter concept. This had a couple issues:
- Part of the state of an entity/value object is "detached" and lives outside the entity/value object
- As a Spring Batch user, when you have a reference to a
JobParameter, you cannot get its name without having to look into the parentJobParameters
The main change in v6 is that the name of a job parameter is now part of the JobParameter class which is now a record and the JobParameters class now holds a Set<JobParameter> instead of a Map from "name" -> "nameless job parameter".
More details about this change can be found in https://github.com/spring-projects/spring-batch/issues/5010.
The JobParametersIncrementer concept is a useful abstraction to use when there is a natural sequence of job instances (hourly, daily, etc). The goal of this abstraction is to bootstrap the initial set of job parameters and let the framework calculate the parameters of the next instance in the sequence. This was clear since the initial design of the JobOperator#startNextInstance(String jobName) method (notice the lack of job parameters in the signature). The concept is similar to database sequences that are initialized once by the user and incremented automatically by the database system (ie not altered by the user anymore). Therefore, it does not make sense to provide job parameters when using an incrementer. If someone starts to modify the sequence's logic and altering job parameters in between instances, (s)he should not use an incrementer in the first place.
Starting from v6, When a job parameters incrementer is attached to a job definition, the parameters of the next instance will be calculated by the framework, and any additional parameters supplied by the user will be ignored with a warning.
Please refer to https://github.com/spring-projects/spring-batch/issues/4910 for more details about this change.
- The sequence
BATCH_JOB_SEQwas renamed toBATCH_JOB_INSTANCE_SEQ
The usage of Micrometer's global static meter registry was removed. It is now required to configure an ObservationRegistry as a bean in the application context to collect batch metrics. Here is a typical configuration:
@Configuration
@EnableBatchProcessing
static class MyJobConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder(jobRepository)
// job flow omitted
.build();
}
@Bean
public ObservationRegistry observationRegistry(MeterRegistry meterRegistry) {
ObservationRegistry observationRegistry = ObservationRegistry.create();
observationRegistry.observationConfig()
.observationHandler(new DefaultMeterObservationHandler(meterRegistry));
return observationRegistry;
}
// Defining the MeterRegistry as a bean is up to the user
@Bean
public SimpleMeterRegistry meterRegistry() {
return new SimpleMeterRegistry();
}
}
A complete example can be found in ChunkOrientedStepObservabilityIntegrationTests
- The
batch:XML namespace is deprecated in favor of Java configuration style. You can continue using the XML configuration style, but thebatch:namespace will not evolve anymore and is scheduled for removal in v7 - Modular configurations through the
@EnableBatchProcessing(modular = true)is deprecated in favor of Spring's context hierarchies andGroupAwareJobs, and is scheduled for removal in v6.2 - JUnit 4 support is now deprecated when using
@SpringBatchTestin favor of JUnit 5+.
The following APIs have been deprecated in version 6.0:
org.springframework.batch.core.step.item.SkipOverflowExceptionorg.springframework.batch.core.step.item.ForceRollbackForWriteSkipExceptionorg.springframework.batch.core.step.StepLocatorStepFactoryBeanorg.springframework.batch.support.transaction.TransactionAwareProxyFactoryFaultTolerantStepBuilderSimpleStepBuilderBatchListenerFactoryHelperFaultTolerantStepFactoryBeanSimpleStepFactoryBeanBatchRetryTemplateChunkMonitorChunkOrientedTaskletChunkProcessorChunkProviderDefaultItemFailureHandlerFaultTolerantChunkProcessorFaultTolerantChunkProviderKeyGeneratorSimpleChunkProcessorSimpleChunkProviderSimpleRetryExceptionHandlerLimitCheckingItemSkipPolicy-
org.springframework.batch.core.repository.support.JobRepositoryFactoryBean: renamed toJdbcJobRepositoryFactoryBean -
org.springframework.batch.core.repository.explore.support.JobExplorerFactoryBean: renamed toJdbcJobExplorerFactoryBean org.springframework.batch.core.configuration.annotation.AutomaticJobRegistrarBeanPostProcessororg.springframework.batch.core.configuration.support.AbstractApplicationContextFactoryorg.springframework.batch.core.configuration.support.ApplicationContextFactoryorg.springframework.batch.core.configuration.support.ApplicationContextJobFactoryorg.springframework.batch.core.configuration.support.AutomaticJobRegistrarorg.springframework.batch.core.configuration.support.ClasspathXmlApplicationContextsFactoryBeanorg.springframework.batch.core.configuration.support.GenericApplicationContextFactoryorg.springframework.batch.core.configuration.support.JobFactoryRegistrationListenerorg.springframework.batch.core.configuration.support.ReferenceJobFactoryorg.springframework.batch.core.configuration.JobFactoryorg.springframework.batch.core.configuration.JobLocatororg.springframework.batch.core.configuration.ListableJobLocatororg.springframework.batch.core.configuration.support.JobLoaderorg.springframework.batch.core.configuration.support.DefaultJobLoaderorg.springframework.batch.core.launch.support.CommandLineJobRunnerorg.springframework.batch.core.launch.support.JvmSystemExiterorg.springframework.batch.core.launch.support.RuntimeExceptionTranslatororg.springframework.batch.core.launch.support.SystemExiterorg.springframework.batch.core.launch.support.TaskExecutorJobLauncherorg.springframework.batch.core.launch.JobLauncherorg.springframework.batch.core.repository.explore.support.AbstractJobExplorerFactoryBeanorg.springframework.batch.core.repository.explore.support.JdbcJobExplorerFactoryBeanorg.springframework.batch.core.repository.explore.support.JobExplorerFactoryBeanorg.springframework.batch.core.repository.explore.support.MongoJobExplorerFactoryBeanorg.springframework.batch.core.repository.explore.support.SimpleJobExplorerorg.springframework.batch.core.repository.explore.JobExplorerorg.springframework.batch.core.resource.StepExecutionSimpleCompletionPolicyorg.springframework.batch.support.PropertiesConverterorg.springframework.batch.test.StepRunnerorg.springframework.batch.item.SkipWrapper
org.springframework.batch.core.repository.JobRepository#getStepExecution(long, long)StepBuilder#chunk(int chunkSize, PlatformTransactionManager transactionManager)StepBuilder#chunk(CompletionPolicy completionPolicy, PlatformTransactionManager transactionManager)StoppableTasklet#stop()JobExplorer#isJobInstanceExists(String jobName, JobParameters jobParameters)JobExplorer#findJobExecutions(JobInstance jobInstance)JobExplorer#findJobInstancesByJobName(String jobName, int start, int count)JobExplorer#findJobInstancesByName(String jobName, int start, int count)SimpleJobExplorer#findJobInstancesByJobName(String jobName, int start, int count)JobInstanceDao#findJobInstancesByName(String jobName, final int start, final int count)JdbcJobInstanceDao#findJobInstancesByName(String jobName, final int start, final int count)MongoJobInstanceDao#findJobInstancesByName(String jobName, final int start, final int count)JobOperator#getExecutions(long instanceId)JobOperator#getJobInstances(String jobName, int start, int count)JobOperator#getJobInstance(String jobName, JobParameters jobParameters)JobOperator#getRunningExecutions(String jobName)JobOperator#getParameters(long executionId)JobOperator#getSummary(long executionId)JobOperator#getStepExecutionSummaries(long executionId)JobOperator#start(String jobName, Properties parameters)JobOperator#getJobNamesJobOperator#restart(long executionId)JobOperator#startNextInstance(String jobName)JobOperator#stop(long executionId)JobOperator#abandon(long jobExecutionId)SimpleJobOperator#start(String jobName, Properties parameters)SimpleJobOperator#getJobNamesSimpleJobOperator#restart(long executionId)SimpleJobOperator#startNextInstance(String jobName)SimpleJobOperator#stop(long executionId)SimpleJobOperator#abandon(long jobExecutionId)SimpleJobOperator#getExecutions(long instanceId)SimpleJobOperator#getJobInstances(String jobName, int start, int count)SimpleJobOperator#getJobInstance(String jobName, JobParameters jobParameters)SimpleJobOperator#getRunningExecutions(String jobName)SimpleJobOperator#getParameters(long executionId)SimpleJobOperator#getSummary(long executionId)SimpleJobOperator#getStepExecutionSummaries(long executionId)SimpleJobOperator#setJobParametersConverter(JobParametersConverter jobParametersConverter)DefaultBatchConfiguration#getJobParametersConverter()EnableBatchProcessing#modularChunk#Chunk(List<? extends W> items, List<SkipWrapper<W>> skips)Chunk#getSkips()Chunk#getErrors()Chunk#skip(Exception e)Chunk#getSkipsSize()Chunk#isEnd()Chunk#setEnd()Chunk#isBusy()Chunk#setBusy(boolean)Chunk#clearSkips()Chunk#getUserData()Chunk#setUserData(Object)Chunk#chunk(CompletionPolicy, PlatformTransactionManager)ChunkListener#beforeChunk(ChunkContext)ChunkListener#afterChunk(ChunkContext)ChunkListener#afterChunkError(ChunkContext)CompositeChunkListener#beforeChunk(ChunkContext)CompositeChunkListener#afterChunk(ChunkContext)CompositeChunkListener#afterChunkError(ChunkContext)
Please refer to the Javadoc of each API for more details about the suggested replacement.
- All APIs defined in the
spring-batch-infrastructuremodule were moved fromorg.springframework.batch.*toorg.springframework.batch.infrastructure.* - All APIs under
org.springframework.batch.core.explorepackage have been moved underorg.springframework.batch.core.repository.explore -
JdbcExecutionContextDao,JdbcJobExecutionDao,JdbcJobInstanceDaoandJdbcStepExecutionDaohave been moved fromorg.springframework.batch.core.repository.daotoorg.springframework.batch.core.repository.dao.jdbc -
MongoExecutionContextDao,MongoJobExecutionDao,MongoJobInstanceDao,MongoStepExecutionDaoandMongoSequenceIncrementerhave been moved fromorg.springframework.batch.core.repository.daotoorg.springframework.batch.core.repository.dao.mongo -
Partitioner,PartitionNameProvider,PartitionStepandStepExecutionAggregatorhave been moved fromorg.springframework.batch.core.partition.supporttoorg.springframework.batch.core.partition -
ChunkListener,ItemProcessListener,ItemReadListener,ItemWriteListener,JobExecutionListener,SkipListener,StepExecutionListenerandStepListenerhave been moved fromorg.springframework.batch.coretoorg.springframework.batch.core.listener -
Job,JobExecution,JobExecutionException,JobInstance,JobInterruptedException,JobKeyGenerator,DefaultJobKeyGenerator,StartLimitExceededExceptionandUnexpectedJobExecutionExceptionhave been moved fromorg.springframework.batch.coretoorg.springframework.batch.core.job -
CompositeJobParametersValidator,DefaultJobParametersValidator,JobParameter,JobParameters,JobParametersBuilder,JobParametersIncrementer,JobParametersInvalidExceptionandJobParametersValidatorhave been moved fromorg.springframework.batch.coretoorg.springframework.batch.core.job.parameters -
Step,StepContributionandStepExecutionhave been moved fromorg.springframework.batch.coretoorg.springframework.batch.core.step -
RunIdIncrementerwas moved fromorg.springframework.batch.core.job.launch.supporttoorg.springframework.batch.core.job.parameters -
DataFieldMaxValueJobParametersIncrementerwas moved fromorg.springframework.batch.core.job.launch.supporttoorg.springframework.batch.core.job.parameters
The following APIs were deprecated in previous versions and have been removed in this release:
- method
org.springframework.batch.core.configuration.support.DefaultBatchConfiguration#getLobHandler - Attribute
lobHandlerRefin@EnableBatchProcessing - Attribute
lob-handlerin XML elementstep - method
org.springframework.batch.core.repository.dao.JdbcExecutionContextDao#setLobHandler - method
org.springframework.batch.core.repository.dao.JdbcJobInstanceDao#setJobIncrementer - method
org.springframework.batch.core.repository.support.JobRepositoryFactoryBean#setLobHandler - method
org.springframework.batch.core.configuration.support.DefaultBatchConfiguration#jobLauncher - method
org.springframework.batch.core.configuration.support.DefaultBatchConfiguration#jobOperator - method
org.springframework.batch.core.configuration.support.DefaultBatchConfiguration#jobRegistryBeanPostProcessor - class
org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor - method
org.springframework.batch.core.explore.support.JobExplorerFactoryBean#setLobHandler - constructor
org.springframework.batch.core.job.builder.JobBuilder#JobBuilder(String name) - class
org.springframework.batch.core.listener.ChunkListenerSupport - class
org.springframework.batch.core.listener.JobExecutionListenerSupport - class
org.springframework.batch.core.listener.SkipListenerSupport - class
org.springframework.batch.core.listener.StepExecutionListenerSupport - method
org.springframework.batch.core.step.builder.AbstractTaskletStepBuilder#throttleLimit - constructor
org.springframework.batch.core.step.builder.StepBuilder#StepBuilder(String name) - method
org.springframework.batch.core.step.builder.TaskletStepBuilder#tasklet(Tasklet tasklet) - method
org.springframework.batch.core.step.factory.SimpleStepFactoryBean#setThrottleLimit - classes
org.springframework.batch.item.data.MongoItemReaderandorg.springframework.batch.item.data.builder.MongoItemReaderBuilder - method
org.springframework.batch.item.data.MongoItemWriter#setDelete - method
org.springframework.batch.item.data.builder.MongoItemWriterBuilder#delete(boolean delete) - class
org.springframework.batch.item.data.Neo4jItemReaderandorg.springframework.batch.item.data.Neo4jItemWriter - method
org.springframework.batch.item.database.support.SqlPagingQueryUtils#generateLimitGroupedSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery, String limitClause) - class
org.springframework.batch.item.database.support.SqlWindowingPagingQueryProvider - class
org.springframework.batch.repeat.listener.RepeatListenerSupport - method
org.springframework.batch.repeat.support.TaskExecutorRepeatTemplate#setThrottleLimit - class
org.springframework.batch.support.SystemPropertyInitializer - constructor
org.springframework.batch.integration.chunk.RemoteChunkingManagerStepBuilder#RemoteChunkingManagerStepBuilder(String stepName) - method
org.springframework.batch.integration.chunk.RemoteChunkingManagerStepBuilder#RemoteChunkingManagerStepBuilder repository(JobRepository jobRepository) - constructor
org.springframework.batch.integration.partition.RemotePartitioningManagerStepBuilder#RemotePartitioningManagerStepBuilder(String stepName) - constructor
org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilder#RemotePartitioningWorkerStepBuilder(String name) - method
org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilder#RemotePartitioningWorkerStepBuilder repository(JobRepository jobRepository) - method
org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilder#tasklet(Tasklet tasklet) - method
org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilder#chunk(CompletionPolicy completionPolicy)
- The class
org.springframework.batch.integration.chunk.ChunkHandlerwas renamed toorg.springframework.batch.integration.chunk.ChunkRequestHandler - The setter
org.springframework.batch.core.step.job.JobStep#setJobLauncher(JobLauncher jobLauncher)was renamed tosetJobOperator(JobOperator jobOperator)and now requires aJobOperatorinstead of aJobLauncher - The setter
org.springframework.batch.core.step.builder.JobStepBuilder#launcher(JobLauncher jobLauncher)was renamed tooperator(JobOperator jobOperator)and now requires aJobOperatorinstead of aJobLauncher - The attribute
job-launcherof the XML elementstep.jobinspring-batch.xsdwas renamed tojob-operatorand now requires aJobOperatorinstead of aJobLauncher - The constructor
org.springframework.batch.integration.launch.JobLaunchingGateway(JobLauncher jobLauncher)now accepts aJobOperatorinstead of aJobLauncher -
org.springframework.batch.integration.launch.JobLaunchingMessageHandler(JobLauncher jobLauncher)now accepts aJobOperatorinstead of aJobLauncher - The attribute `` of the XML element
job-launching-gatewayin `spring-batch-integration.xsd` was renamed to `job-operator` and now requires a `JobOperator` instead of a `JobLauncher` - The setter
org.springframework.batch.core.step.tasklet.SystemCommandTasklet#setJobExplorer(JobExplorer jobExplorer)was renamed tosetJobRepository(JobRepository jobRepository)and now requires aJobRepositoryinstead of aJobExplorer - The constructor
org.springframework.batch.core.partition.support.RemoteStepExecutionAggregator(JobExplorer jobExplorer)now accepts aJobRepositoryinstead of aJobExplorer - The setter
org.springframework.batch.core.partition.support.RemoteStepExecutionAggregator#setJobExplorer(JobExplorer jobExplorer)was renamed tosetJobRepository(JobRepository jobRepository)and now requires aJobRepositoryinstead of aJobExplorer