Infrastructure configuration

This section documents the current Spring Batch line — 6.0.x, on Spring Framework 7 and Spring Boot 4.1.x, with a Java 17+ baseline — as published at the Spring Batch reference documentation. No specific patch version is pinned. Some surfaces (Spring Cloud Task and Spring Cloud Data Flow orchestration, the deployer-based partition handler, and JSR-352) are linked, not documented in depth.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

Before a job can run, three infrastructure beans must exist: a JobRepository, a PlatformTransactionManager and a JobOperator. Under Spring Boot they are auto-configured; this page covers what they are, how to take manual control, and what changed in 6.0.

Leave @EnableBatchProcessing off under Spring Boot

@EnableBatchProcessing is the annotation that bootstraps the batch infrastructure by hand. Adding it to a Spring Boot application switches Boot’s batch auto-configuration off — Boot deliberately backs away when it sees the annotation, and the carefully assembled defaults (a JobRepository on the application DataSource, schema initialisation, spring.batch.* property binding, the startup runner) all disappear.

So, under Spring Boot:

@SpringBootApplication          // no @EnableBatchProcessing here
public class BatchApplication {
    public static void main(String[] args) {
        SpringApplication.run(BatchApplication.class, args);
    }
}

Boot’s own documentation states the rule at Batch Applications; the concrete walk-through of what the starter auto-configures is on Spring Batch (SpringBoot Reference) and is not restated here.

What the annotation does in 6.0

Outside Spring Boot — a plain Spring application, or a Boot application that genuinely wants to assemble the infrastructure itself — @EnableBatchProcessing is still the entry point, and 6.0 splits its responsibilities:

  • @EnableBatchProcessing now carries the common attributes only, such as taskExecutorRef, jobRepositoryRef and the transaction attributes;

  • the store-specific configuration moved to dedicated annotations — @EnableJdbcJobRepository and @EnableMongoJobRepository.

@Configuration
@EnableBatchProcessing(taskExecutorRef = "batchTaskExecutor")
@EnableJdbcJobRepository(dataSourceRef = "batchDataSource", tablePrefix = "BATCH_")
public class ManualBatchInfrastructure {

    @Bean
    public TaskExecutor batchTaskExecutor() {
        return new SimpleAsyncTaskExecutor("batch-");
    }
}
@Configuration
@EnableBatchProcessing
@EnableMongoJobRepository(mongoOperationsRef = "mongoTemplate")
public class MongoBatchInfrastructure {
}

DefaultBatchConfiguration for full control

When individual beans must be replaced rather than merely parameterised, extend DefaultBatchConfiguration and override the factory methods. This is the replacement for the removed BatchConfigurer interface — code that implemented BatchConfigurer in 4.x has no equivalent in 6.0 and must be migrated to this style.

The hooks the class actually exposes are getJobRegistry(), getObservationRegistry(), getTransactionManager(), getTaskExecutor() and getJobParametersConverter(). The JDBC-specific settings that used to be overridable methods — the datasource, the table prefix, the isolation level used when creating a JobExecution — are now attributes of @EnableJdbcJobRepository instead, so they are set there rather than overridden:

@Configuration
// the JDBC-specific settings are attributes of the annotation in 6.0
@EnableJdbcJobRepository(
        dataSourceRef = "batchDataSource",
        tablePrefix = "BATCH_",
        isolationLevelForCreate = Isolation.READ_COMMITTED)   // relax SERIALIZABLE deliberately
public class BatchInfrastructure extends DefaultBatchConfiguration {

    @Override
    protected PlatformTransactionManager getTransactionManager() {
        return new DataSourceTransactionManager(batchDataSource());
    }

    @Bean
    public DataSource batchDataSource() {
        return DataSourceBuilder.create()
                .url("jdbc:postgresql://localhost:5432/batchmeta")
                .username("batch")
                .build();
    }
}

Extending DefaultBatchConfiguration is also mutually exclusive with Boot’s auto-configuration for the beans it defines — which is the point: it is chosen when the defaults are not wanted.

The resourceless default

Spring Batch 6.0 makes the infrastructure work with no database at all. When no DataSource is available, the ResourcelessJobRepository and ResourcelessTransactionManager are used: metadata is held in memory (in fact largely discarded), so a job can be written, run and demonstrated with nothing but the framework on the classpath.

@Configuration
public class ResourcelessInfrastructure {

    @Bean
    public JobRepository jobRepository() {
        return new ResourcelessJobRepository();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new ResourcelessTransactionManager();
    }
}

This is excellent for samples, prototypes and unit tests, and it is what makes a "hello world" job runnable without provisioning anything. It is not suitable for production: with no persisted metadata there is no restart, no history and no audit trail. Anything that must survive a crash needs the JDBC or MongoDB repository described in The job repository & metadata schema.

The 6.0 interface unification

Three long-standing sources of confusion were removed in 6.0:

Change What it means in code

JobRepository extends JobExplorer

The read operations that used to require a separate JobExplorer bean are now on the repository itself. Inject JobRepository and call getJobInstances, getJobExecutions, getLastJobExecution directly. A separate JobExplorer is no longer needed.

JobOperator extends JobLauncher

JobOperator is now the single launching and controlling interface: start, stop, restart, startNextInstance, abandon, recover. TaskExecutorJobOperator is the standard implementation. Code that injected a JobLauncher can inject a JobOperator instead.

JobRegistry is optional

Jobs defined as beans are registered automatically, so an explicit JobRegistry plus JobRegistryBeanPostProcessor wiring is no longer required. Inject a JobRegistry only when jobs must be looked up by name at runtime.

@Service
public class BatchAdminService {

    private final JobOperator jobOperator;     // launching AND control
    private final JobRepository jobRepository; // launching metadata AND queries

    public BatchAdminService(JobOperator jobOperator, JobRepository jobRepository) {
        this.jobOperator = jobOperator;
        this.jobRepository = jobRepository;
    }

    public JobExecution lastRunOf(String jobName) {
        JobInstance instance = jobRepository.getLastJobInstance(jobName);
        return instance == null ? null : jobRepository.getLastJobExecution(instance);
    }
}

Using these interfaces to launch and control jobs is covered in Running a job and Stopping, restart & recovery. The full list of 6.0 changes is at What’s new in Spring Batch 6.0.