I'm developing a Spring Boot 3.3.5 application using Spring Batch. I need to separate the Spring Batch database from the main application database. Additionally, I need to ensure that jobs do not run at application startup, as I want to execute them explicitly and programmatically. I tried using the property spring.batch.job.enabled=false, but the jobs still run at runtime. Perhaps something in my configuration is causing this issue.
Here is the configuration for multiple data sources:
@Configuration
@Profile({"!test"})
public class DataSourceFactory {
@Bean
@BatchDataSource
public DataSource h2Datasource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:org/springframework/batch/core/schema-drop-h2.sql")
.addScript("/org/springframework/batch/core/schema-h2.sql")
.build();
}
@Bean
@BatchTransactionManager
public PlatformTransactionManager batchTransactionManager() {
return new JdbcTransactionManager(h2Datasource());
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSourceProperties oracleDatasourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource.hikari")
public DataSource oracleDatasource() {
return oracleDatasourceProperties().initializeDataSourceBuilder().build();
}
@Bean
@Primary
public PlatformTransactionManager transactionManager() {
return new JdbcTransactionManager(oracleDatasource());
}
}
This the job:
@Configuration
@RequiredArgsConstructor
public class NotificationJobConfig {
private final JobRepository jobRepository;
...
@Bean
public Job notificationJob() {
return new JobBuilder(NOTIFICATION_JOB, jobRepository)
...
.build();
}
}
The is the service running the job:
@Service
@Slf4j
public class JobServiceImpl implements JobService {
@Autowired
private JobLauncher jobLauncher;
@Autowired
@Qualifier(NotificationJobConfig.NOTIFICATION_JOB)
private Job notificationJob;
@Override
public void runNotification() {
try {
JobParameters jobParameters = new JobParametersBuilder().addLocalDateTime("timestamp", LocalDateTime.now()).toJobParameters();
jobLauncher.run(notificationJob, jobParameters);
} catch (Exception e) {
log.error("Error starting notification job: {}", e.getMessage(), e);
}
}
}
I made a second solution adding a class configuration with @EnableBatchProcessing:
@Configuration
@EnableBatchProcessing
public class BatchConfig {
}
but in this case spring complains with this message:
Field jobLauncher in it.coop.coopitalia.rs.service.JobServiceImpl required a bean named 'dataSource' that could not be found.
At the end I tried to use DefaultBatchConfiguration instead of @EnableBatchProcessing like this:
@Configuration
public class BatchConfig extends DefaultBatchConfiguration {
@Autowired
@BatchDataSource
private DataSource batchDatasource;
@Autowired
@BatchTransactionManager
private PlatformTransactionManager batchTransactionManager;
@Override
protected DataSource getDataSource() {
return batchDatasource;
}
@Override
protected PlatformTransactionManager getTransactionManager() {
return this.batchTransactionManager;
}
@Bean
public JobLauncher jobLauncher() {
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
try {
jobLauncher.setJobRepository(jobRepository());
jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
jobLauncher.afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
return jobLauncher;
}
}
But again the problem is that job automatically run at application start-up.
So, there is something I'm doing wrong... any ideas?
It seems like the spring.batch.job.enabled=false
property is not taken into account in your case. I gave that a quick test and things seem to work as expected:
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.batch.BatchDataSource;
import org.springframework.boot.autoconfigure.batch.BatchTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.support.JdbcTransactionManager;
import javax.sql.DataSource;
@SpringBootApplication
public class SO79492302Application {
public static void main(String[] args) {
SpringApplication.run(SO79492302Application.class, args);
}
@Bean
public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
Step myStep = new StepBuilder("myStep", jobRepository)
.tasklet((contribution, chunkContext)
-> { System.out.println("Hello world!");
return RepeatStatus.FINISHED;
}, transactionManager)
.build();
return new JobBuilder("myJob", jobRepository)
.start(myStep)
.build();
}
// batch infrastructure
@Bean
@BatchDataSource
public DataSource batchDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("/org/springframework/batch/core/schema-h2.sql")
.build();
}
@Bean
@BatchTransactionManager
public JdbcTransactionManager batchTransactionManager(@Qualifier("batchDataSource") DataSource batchDataSource) {
return new JdbcTransactionManager(batchDataSource);
}
// business infrastructure
@Bean
@Primary
public DataSource datasource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
The pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-batch-resourceles-job-repository</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-batch-resourceles-job-repository</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The application.properties
file:
spring.batch.job.enabled=false
prints:
:: Spring Boot :: (v3.4.3)
2025-03-07T08:26:54.089-05:00 INFO 21002 --- [ main] c.e.s.SO79492302Application : Starting SO79492302Application using Java 21.0.2 with PID 21002
2025-03-07T08:26:54.090-05:00 INFO 21002 --- [ main] c.e.s.SO79492302Application : No active profile set, falling back to 1 default profile: "default"
2025-03-07T08:26:54.333-05:00 INFO 21002 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
2025-03-07T08:26:54.430-05:00 INFO 21002 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
2025-03-07T08:26:54.543-05:00 INFO 21002 --- [ main] c.e.s.SO79492302Application : Started SO79492302Application in 0.628 seconds (process running for 0.797)
2025-03-07T08:26:54.546-05:00 INFO 21002 --- [ionShutdownHook] o.s.j.d.e.EmbeddedDatabaseFactory : Shutting down embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false'
2025-03-07T08:26:54.547-05:00 INFO 21002 --- [ionShutdownHook] o.s.j.d.e.EmbeddedDatabaseFactory : Shutting down embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false'
The job did not run on startup as expected.