How to customize the Spring Batch default configuration without breaking autoconfiguration

35 views Asked by At

How can I customize Spring Batch's DefaultBatchConfiguration without breaking the autoconfiguration provided by Spring Boot in SpringBootBatchConfiguration?

I am using a Spring Batch job in a Spring Boot application, with the following configuration:

@Configuration
public class MyJobConfiguration {

    @Bean
    public Tasklet myTasklet() {
        return (contribution, chunkContext) -> {
            System.out.println("execute myTasklet");
            return RepeatStatus.FINISHED;
        };
    }

    @Bean
    public Step myStep(JobRepository jobRepository, Tasklet myTasklet, PlatformTransactionManager transactionManager) {
        return new StepBuilder("myStep", jobRepository)
                .tasklet(myTasklet, transactionManager)
                .build();
    }

    @Bean
    public Job myJob(JobRepository jobRepository, Step myStep) {
        return new JobBuilder("myJob", jobRepository)
                .start(myStep)
                .build();
    }
}

I test the job with @SpringBatchTest like so:

@SpringBatchTest
@ContextConfiguration(classes = MyJobConfiguration.class)
@EnableAutoConfiguration
class MyJobConfigurationTest {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Autowired
    private JobRepositoryTestUtils jobRepositoryTestUtils;

    @BeforeEach
    public void setup(@Autowired Job jobUnderTest) {
        this.jobLauncherTestUtils.setJob(jobUnderTest); // this is optional if the job is unique
        this.jobRepositoryTestUtils.removeJobExecutions();
    }

    @Test
    public void testMyJob() throws Exception {
        // given
        JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters();

        // when
        JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);

        // then
        Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
    }
}

This is pretty standard and it works as expected. As can be seen from the annotation @EnableAutoConfiguration, it makes use of Spring Boot's autoconfiguration for Spring Batch, which for instance guarantees that the database schema is initialized in the in-memory database for the test.

I would like to customize the batch configuration to allow asynchronous job execution. I modified my configuration in the following way:

@Configuration
public class MyJobConfiguration extends DefaultBatchConfiguration {

    public static final int MAX_BATCH_TASK_EXECUTOR_POOL_SIZE = 20;

    @Override
    public TaskExecutor getTaskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setMaxPoolSize(MAX_BATCH_TASK_EXECUTOR_POOL_SIZE);
        threadPoolTaskExecutor.afterPropertiesSet();
        return threadPoolTaskExecutor;
    }

The javadoc of DefaultBatchConfiguration says:

Customization is possible by extending the class and overriding getters.

That's why I chose this approach. However, this seems to knock out Spring Boot's autoconfiguration for Spring Batch. The spring batch test fails because the database schema initialization is not done anymore. The condition evaluation report confirms this.

Is it possible to customize the Spring Batch configuration this way?

When relying on Spring Boot's autoconfiguration for Spring Batch, is there another way to add customizations?

Is it preferrable to configure additional joblaunchers and not customize the behaviour of the default joblauncher?

1

There are 1 answers

1
JUDE On

Instead of extending DefaultBatchConfiguration, you can define custom beans for specific components you want to customize. For example, you can define a custom TaskExecutor bean without extending DefaultBatchConfiguration. This allows you to retain other autoconfigured beans provided by Spring Boot.

@Configuration
public class MyJobConfiguration {

    @Bean
    public TaskExecutor myTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setMaxPoolSize(MAX_BATCH_TASK_EXECUTOR_POOL_SIZE);
        taskExecutor.afterPropertiesSet();
        return taskExecutor;
    }
}