Improve batch infrastructure configuration

Before this commit, EnableBatchProcessing was tied to a JDBC
infrastructure. Therefore, it was impossible to use a non-JDBC
job repository with that annotation.

This commit removes the dependency to a JDBC infrastructure from
EnableBatchProcessing and introduces new annotations to configure
specific job repository implementations. It also updates the
programmatic way of configuring infrastructure beans with a base
configuration class for each supported job repository implementation.

NB: The XML namespace was not changed accordingly as the XSD will not
be updated starting from v6.

Resolves #4718
This commit is contained in:
Mahmoud Ben Hassine
2025-05-22 11:38:29 +02:00
parent 25525ff98d
commit f7fcfaa4fd
33 changed files with 773 additions and 432 deletions

View File

@@ -25,14 +25,16 @@ import org.springframework.batch.core.configuration.support.DefaultJobLoader;
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.support.JdbcJobRepositoryFactoryBean;
import org.springframework.batch.core.repository.support.MongoJobRepositoryFactoryBean;
import org.springframework.batch.core.repository.support.ResourcelessJobRepository;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.log.LogMessage;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
@@ -52,6 +54,8 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
private static final String JOB_REPOSITORY = "jobRepository";
private static final String JOB_OPERATOR = "jobOperator";
private static final String JOB_REGISTRY = "jobRegistry";
private static final String JOB_LOADER = "jobLoader";
@@ -64,7 +68,7 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
EnableBatchProcessing batchAnnotation = importingClassMetadata.getAnnotations()
.get(EnableBatchProcessing.class)
.synthesize();
registerJobRepository(registry, batchAnnotation);
registerJobRepository(registry, importingClassMetadata);
registerJobRegistry(registry);
registerJobRegistrySmartInitializingSingleton(registry);
registerJobOperator(registry, batchAnnotation);
@@ -82,65 +86,126 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
}
}
private void registerJobRepository(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
private void registerJobRepository(BeanDefinitionRegistry registry, AnnotationMetadata importingClassMetadata) {
if (registry.containsBeanDefinition(JOB_REPOSITORY)) {
LOGGER.info("Bean jobRepository already defined in the application context, skipping"
+ " the registration of a jobRepository");
return;
}
if (importingClassMetadata.hasAnnotation(EnableJdbcJobRepository.class.getName())) {
registerJdbcJobRepository(registry, importingClassMetadata);
}
else {
if (importingClassMetadata.hasAnnotation(EnableMongoJobRepository.class.getName())) {
registerMongoJobRepository(registry, importingClassMetadata);
}
else {
registerDefaultJobRepository(registry);
}
}
}
private void registerJdbcJobRepository(BeanDefinitionRegistry registry, AnnotationMetadata importingClassMetadata) {
EnableJdbcJobRepository jdbcJobRepositoryAnnotation = importingClassMetadata.getAnnotations()
.get(EnableJdbcJobRepository.class)
.synthesize();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(JdbcJobRepositoryFactoryBean.class);
// set mandatory properties
String dataSourceRef = batchAnnotation.dataSourceRef();
String dataSourceRef = jdbcJobRepositoryAnnotation.dataSourceRef();
beanDefinitionBuilder.addPropertyReference("dataSource", dataSourceRef);
String transactionManagerRef = batchAnnotation.transactionManagerRef();
String transactionManagerRef = jdbcJobRepositoryAnnotation.transactionManagerRef();
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
// set optional properties
String executionContextSerializerRef = batchAnnotation.executionContextSerializerRef();
String executionContextSerializerRef = jdbcJobRepositoryAnnotation.executionContextSerializerRef();
if (registry.containsBeanDefinition(executionContextSerializerRef)) {
beanDefinitionBuilder.addPropertyReference("serializer", executionContextSerializerRef);
}
String conversionServiceRef = batchAnnotation.conversionServiceRef();
String conversionServiceRef = jdbcJobRepositoryAnnotation.conversionServiceRef();
if (registry.containsBeanDefinition(conversionServiceRef)) {
beanDefinitionBuilder.addPropertyReference("conversionService", conversionServiceRef);
}
String incrementerFactoryRef = batchAnnotation.incrementerFactoryRef();
String incrementerFactoryRef = jdbcJobRepositoryAnnotation.incrementerFactoryRef();
if (registry.containsBeanDefinition(incrementerFactoryRef)) {
beanDefinitionBuilder.addPropertyReference("incrementerFactory", incrementerFactoryRef);
}
String jobKeyGeneratorRef = batchAnnotation.jobKeyGeneratorRef();
if (registry.containsBeanDefinition(jobKeyGeneratorRef)) {
beanDefinitionBuilder.addPropertyReference("jobKeyGenerator", jobKeyGeneratorRef);
}
String charset = batchAnnotation.charset();
String charset = jdbcJobRepositoryAnnotation.charset();
if (charset != null) {
beanDefinitionBuilder.addPropertyValue("charset", Charset.forName(charset));
}
String tablePrefix = batchAnnotation.tablePrefix();
String tablePrefix = jdbcJobRepositoryAnnotation.tablePrefix();
if (tablePrefix != null) {
beanDefinitionBuilder.addPropertyValue("tablePrefix", tablePrefix);
}
String isolationLevelForCreate = batchAnnotation.isolationLevelForCreate();
if (isolationLevelForCreate != null) {
beanDefinitionBuilder.addPropertyValue("isolationLevelForCreate", isolationLevelForCreate);
}
String databaseType = batchAnnotation.databaseType();
String databaseType = jdbcJobRepositoryAnnotation.databaseType();
if (StringUtils.hasText(databaseType)) {
beanDefinitionBuilder.addPropertyValue("databaseType", databaseType);
}
beanDefinitionBuilder.addPropertyValue("maxVarCharLength", batchAnnotation.maxVarCharLength());
beanDefinitionBuilder.addPropertyValue("clobType", batchAnnotation.clobType());
String jdbcOperationsRef = jdbcJobRepositoryAnnotation.jdbcOperationsRef();
if (registry.containsBeanDefinition(jdbcOperationsRef)) {
beanDefinitionBuilder.addPropertyReference("jdbcOperations", jdbcOperationsRef);
}
beanDefinitionBuilder.addPropertyValue("maxVarCharLength", jdbcJobRepositoryAnnotation.maxVarCharLength());
beanDefinitionBuilder.addPropertyValue("clobType", jdbcJobRepositoryAnnotation.clobType());
beanDefinitionBuilder.addPropertyValue("validateTransactionState",
jdbcJobRepositoryAnnotation.validateTransactionState());
Isolation isolationLevelForCreate = jdbcJobRepositoryAnnotation.isolationLevelForCreate();
if (isolationLevelForCreate != null) {
beanDefinitionBuilder.addPropertyValue("isolationLevelForCreateEnum", isolationLevelForCreate);
}
String jobKeyGeneratorRef = jdbcJobRepositoryAnnotation.jobKeyGeneratorRef();
if (registry.containsBeanDefinition(jobKeyGeneratorRef)) {
beanDefinitionBuilder.addPropertyReference("jobKeyGenerator", jobKeyGeneratorRef);
}
registry.registerBeanDefinition(JOB_REPOSITORY, beanDefinitionBuilder.getBeanDefinition());
}
private void registerMongoJobRepository(BeanDefinitionRegistry registry,
AnnotationMetadata importingClassMetadata) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoJobRepositoryFactoryBean.class);
EnableMongoJobRepository mongoJobRepositoryAnnotation = importingClassMetadata.getAnnotations()
.get(EnableMongoJobRepository.class)
.synthesize();
String mongoOperationsRef = mongoJobRepositoryAnnotation.mongoOperationsRef();
if (registry.containsBeanDefinition(mongoOperationsRef)) {
beanDefinitionBuilder.addPropertyReference("mongoOperations", mongoOperationsRef);
}
String transactionManagerRef = mongoJobRepositoryAnnotation.transactionManagerRef();
if (registry.containsBeanDefinition(transactionManagerRef)) {
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
}
Isolation isolationLevelForCreate = mongoJobRepositoryAnnotation.isolationLevelForCreate();
if (isolationLevelForCreate != null) {
beanDefinitionBuilder.addPropertyValue("isolationLevelForCreate", isolationLevelForCreate);
}
String jobKeyGeneratorRef = mongoJobRepositoryAnnotation.jobKeyGeneratorRef();
if (registry.containsBeanDefinition(jobKeyGeneratorRef)) {
beanDefinitionBuilder.addPropertyReference("jobKeyGenerator", jobKeyGeneratorRef);
}
beanDefinitionBuilder.addPropertyValue("validateTransactionState",
mongoJobRepositoryAnnotation.validateTransactionState());
registry.registerBeanDefinition(JOB_REPOSITORY, beanDefinitionBuilder.getBeanDefinition());
}
private void registerDefaultJobRepository(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(ResourcelessJobRepository.class);
registry.registerBeanDefinition(JOB_REPOSITORY, beanDefinitionBuilder.getBeanDefinition());
}
@@ -171,7 +236,7 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
}
private void registerJobOperator(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
if (registry.containsBeanDefinition("jobOperator")) {
if (registry.containsBeanDefinition(JOB_OPERATOR)) {
LOGGER.info("Bean jobOperator already defined in the application context, skipping"
+ " the registration of a jobOperator");
return;
@@ -186,12 +251,16 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
beanDefinitionBuilder.addPropertyReference(JOB_REGISTRY, JOB_REGISTRY);
// set optional properties
String taskExecutorRef = batchAnnotation.taskExecutorRef();
if (registry.containsBeanDefinition(taskExecutorRef)) {
beanDefinitionBuilder.addPropertyReference("taskExecutor", taskExecutorRef);
}
String jobParametersConverterRef = batchAnnotation.jobParametersConverterRef();
if (registry.containsBeanDefinition(jobParametersConverterRef)) {
beanDefinitionBuilder.addPropertyReference("jobParametersConverter", jobParametersConverterRef);
}
registry.registerBeanDefinition("jobOperator", beanDefinitionBuilder.getBeanDefinition());
registry.registerBeanDefinition(JOB_OPERATOR, beanDefinitionBuilder.getBeanDefinition());
}
private void registerAutomaticJobRegistrar(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {

View File

@@ -15,27 +15,15 @@
*/
package org.springframework.batch.core.configuration.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.ApplicationContextFactory;
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;
import org.springframework.batch.core.configuration.support.ScopeConfiguration;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
import org.springframework.batch.support.DatabaseType;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.PlatformTransactionManager;
import java.lang.annotation.*;
/**
* <p>
@@ -67,9 +55,10 @@ import org.springframework.transaction.PlatformTransactionManager;
* }
* </pre>
*
* This annotation configures JDBC-based Batch infrastructure beans, so you must provide a
* {@link DataSource} and a {@link PlatformTransactionManager} as beans in the application
* context.
* By default,this annotation configures a resouceless batch infrastructure (ie based on a
* {@link org.springframework.batch.core.repository.support.ResourcelessJobRepository} and
* a
* {@link org.springframework.batch.support.transaction.ResourcelessTransactionManager}).
*
* Note that only one of your configuration classes needs to have the
* <code>&#064;EnableBatchProcessing</code> annotation. Once you have an
@@ -83,8 +72,6 @@ import org.springframework.transaction.PlatformTransactionManager;
* <ul>
* <li>a {@link JobRepository} (bean name "jobRepository" of type
* {@link org.springframework.batch.core.repository.support.SimpleJobRepository})</li>
* <li>a {@link JobLauncher} (bean name "jobLauncher" of type
* {@link TaskExecutorJobLauncher})</li>
* <li>a {@link JobRegistry} (bean name "jobRegistry" of type
* {@link org.springframework.batch.core.configuration.support.MapJobRegistry})</li>
* <li>a {@link org.springframework.batch.core.launch.JobOperator} (bean name
@@ -142,8 +129,8 @@ import org.springframework.transaction.PlatformTransactionManager;
* </job>
* <beans:bean id="dataSource" .../>
* <beans:bean id="transactionManager" .../>
* <beans:bean id="jobLauncher" class=
"org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
* <beans:bean id="jobOperator" class=
"org.springframework.batch.core.launch.support.TaskExecutorJobOperator">
* <beans:property name="jobRepository" ref="jobRepository" />
* </beans:bean>
* </batch>
@@ -173,102 +160,26 @@ public @interface EnableBatchProcessing {
boolean modular() default false;
/**
* Set the data source to use in the job repository and job explorer.
* @return the bean name of the data source to use. Default to {@literal dataSource}.
*/
String dataSourceRef() default "dataSource";
/**
* Set the type of the data source to use in the job repository. The default type will
* be introspected from the datasource's metadata.
* @since 5.1
* @see DatabaseType
* @return the type of data source.
*/
String databaseType() default "";
/**
* Set the transaction manager to use in the job repository.
* @return the bean name of the transaction manager to use. Defaults to
* {@literal transactionManager}
*/
String transactionManagerRef() default "transactionManager";
/**
* Set the execution context serializer to use in the job repository and job explorer.
* @return the bean name of the execution context serializer to use. Default to
* {@literal executionContextSerializer}.
*/
String executionContextSerializerRef() default "executionContextSerializer";
/**
* The charset to use in the job repository and job explorer
* @return the charset to use. Defaults to {@literal UTF-8}.
*/
String charset() default "UTF-8";
/**
* The Batch tables prefix. Defaults to {@literal "BATCH_"}.
* @return the Batch table prefix
*/
String tablePrefix() default AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
/**
* The maximum length of exit messages in the database.
* @return the maximum length of exit messages in the database
*/
int maxVarCharLength() default AbstractJdbcBatchMetadataDao.DEFAULT_EXIT_MESSAGE_LENGTH;
/**
* The incrementer factory to use in various DAOs.
* @return the bean name of the incrementer factory to use. Defaults to
* {@literal incrementerFactory}.
*/
String incrementerFactoryRef() default "incrementerFactory";
/**
* The generator that determines a unique key for identifying job instance objects
* @return the bean name of the job key generator to use. Defaults to
* {@literal jobKeyGenerator}.
*
* @since 5.1
*/
String jobKeyGeneratorRef() default "jobKeyGenerator";
/**
* The type of large objects.
* @return the type of large objects.
*/
int clobType() default Types.CLOB;
/**
* Set the isolation level for create parameter value. Defaults to
* {@literal ISOLATION_SERIALIZABLE}.
* @return the value of the isolation level for create parameter
*/
String isolationLevelForCreate() default "ISOLATION_SERIALIZABLE";
/**
* Set the task executor to use in the job launcher.
* Set the task executor to use in the job operator.
* @return the bean name of the task executor to use. Defaults to
* {@literal taskExecutor}
*/
String taskExecutorRef() default "taskExecutor";
/**
* Set the conversion service to use in the job repository and job explorer. This
* service is used to convert job parameters from String literal to typed values and
* vice versa.
* @return the bean name of the conversion service to use. Defaults to
* {@literal conversionService}
* Set the transaction manager to use in the job operator.
* @return the bean name of the transaction manager to use. Defaults to
* {@literal transactionManager}
*/
String conversionServiceRef() default "conversionService";
String transactionManagerRef() default "transactionManager";
/**
* Set the {@link JobParametersConverter} to use in the job operator.
* @return the bean name of the job parameters converter to use. Defaults to
* {@literal jobParametersConverter}
* @deprecated since 6.0 with no replacement. Scheduled for removal in 6.2 or later
*/
@Deprecated(since = "6.0", forRemoval = true)
String jobParametersConverterRef() default "jobParametersConverter";
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.configuration.annotation;
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
import org.springframework.batch.support.DatabaseType;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.sql.Types;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableJdbcJobRepository {
/**
* Set the type of the data source to use in the job repository. The default type will
* be introspected from the datasource's metadata.
* @since 5.1
* @see DatabaseType
* @return the type of data source.
*/
String databaseType() default "";
/**
* Set the value of the {@code validateTransactionState} parameter. Defaults to
* {@code true}.
* @return true if the transaction state should be validated, false otherwise
*/
boolean validateTransactionState() default true;
/**
* Set the isolation level for create parameter value. Defaults to
* {@link Isolation#SERIALIZABLE}.
* @return the value of the isolation level for create parameter
*/
Isolation isolationLevelForCreate() default Isolation.SERIALIZABLE;
/**
* The charset to use in the job repository
* @return the charset to use. Defaults to {@literal UTF-8}.
*/
String charset() default "UTF-8";
/**
* The Batch tables prefix. Defaults to {@literal "BATCH_"}.
* @return the Batch table prefix
*/
String tablePrefix() default AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
/**
* The maximum length of exit messages in the database.
* @return the maximum length of exit messages in the database
*/
int maxVarCharLength() default AbstractJdbcBatchMetadataDao.DEFAULT_EXIT_MESSAGE_LENGTH;
/**
* The type of large objects.
* @return the type of large objects.
*/
int clobType() default Types.CLOB;
/**
* Set the data source to use in the job repository.
* @return the bean name of the data source to use. Default to {@literal dataSource}.
*/
String dataSourceRef() default "dataSource";
/**
* Set the {@link DataSourceTransactionManager} to use in the job repository.
* @return the bean name of the transaction manager to use. Defaults to
* {@literal transactionManager}
*/
String transactionManagerRef() default "transactionManager";
String jdbcOperationsRef() default "jdbcTemplate";
/**
* The generator that determines a unique key for identifying job instance objects
* @return the bean name of the job key generator to use. Defaults to
* {@literal jobKeyGenerator}.
*
* @since 5.1
*/
String jobKeyGeneratorRef() default "jobKeyGenerator";
/**
* Set the execution context serializer to use in the job repository.
* @return the bean name of the execution context serializer to use. Default to
* {@literal executionContextSerializer}.
*/
String executionContextSerializerRef() default "executionContextSerializer";
/**
* The incrementer factory to use in various DAOs.
* @return the bean name of the incrementer factory to use. Defaults to
* {@literal incrementerFactory}.
*/
String incrementerFactoryRef() default "incrementerFactory";
/**
* Set the conversion service to use in the job repository. This service is used to
* convert job parameters from String literal to typed values and vice versa.
* @return the bean name of the conversion service to use. Defaults to
* {@literal conversionService}
*/
String conversionServiceRef() default "conversionService";
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.configuration.annotation;
import org.springframework.data.mongodb.MongoTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableMongoJobRepository {
String mongoOperationsRef() default "mongoTemplate";
/**
* Set the {@link MongoTransactionManager} to use in the job repository.
* @return the bean name of the transaction manager to use. Defaults to
* {@literal transactionManager}
*/
String transactionManagerRef() default "transactionManager";
/**
* Set the isolation level for create parameter value. Defaults to
* {@link Isolation#SERIALIZABLE}.
* @return the value of the isolation level for create parameter
*/
Isolation isolationLevelForCreate() default Isolation.SERIALIZABLE;
/**
* Set the value of the {@code validateTransactionState} parameter. Defaults to
* {@code true}.
* @return true if the transaction state should be validated, false otherwise
*/
boolean validateTransactionState() default true;
/**
* The generator that determines a unique key for identifying job instance objects
* @return the bean name of the job key generator to use. Defaults to
* {@literal jobKeyGenerator}.
*
*/
String jobKeyGeneratorRef() default "jobKeyGenerator";
}

View File

@@ -15,70 +15,41 @@
*/
package org.springframework.batch.core.configuration.support;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.batch.core.DefaultJobKeyGenerator;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobKeyGenerator;
import org.springframework.batch.core.configuration.BatchConfigurationException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.converter.DateToStringConverter;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.converter.LocalDateTimeToStringConverter;
import org.springframework.batch.core.converter.LocalDateToStringConverter;
import org.springframework.batch.core.converter.LocalTimeToStringConverter;
import org.springframework.batch.core.converter.StringToDateConverter;
import org.springframework.batch.core.converter.StringToLocalDateConverter;
import org.springframework.batch.core.converter.StringToLocalDateTimeConverter;
import org.springframework.batch.core.converter.StringToLocalTimeConverter;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.launch.support.TaskExecutorJobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
import org.springframework.batch.core.repository.dao.DefaultExecutionContextSerializer;
import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
import org.springframework.batch.core.repository.dao.JdbcStepExecutionDao;
import org.springframework.batch.core.repository.support.JdbcJobRepositoryFactoryBean;
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
import org.springframework.batch.support.DatabaseType;
import org.springframework.batch.core.repository.support.ResourcelessJobRepository;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Isolation;
/**
* Base {@link Configuration} class that provides common JDBC-based infrastructure beans
* for enabling and using Spring Batch.
* Base {@link Configuration} class that provides common infrastructure beans for enabling
* and using Spring Batch.
* <p>
* This configuration class configures and registers the following beans in the
* application context:
*
* <ul>
* <li>a {@link JobRepository} named "jobRepository"</li>
* <li>a {@link JobLauncher} named "jobLauncher"</li>
* <li>a {@link JobRegistry} named "jobRegistry"</li>
* <li>a {@link JobOperator} named "JobOperator"</li>
* <li>a {@link ResourcelessJobRepository} named "jobRepository"</li>
* <li>a {@link MapJobRegistry} named "jobRegistry"</li>
* <li>a {@link TaskExecutorJobOperator} named "JobOperator"</li>
* <li>a {@link JobRegistrySmartInitializingSingleton} named
* "jobRegistrySmartInitializingSingleton"</li>
* <li>a {@link org.springframework.batch.core.scope.StepScope} named "stepScope"</li>
@@ -119,44 +90,15 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
}
@Bean
public JobRepository jobRepository() throws BatchConfigurationException {
JdbcJobRepositoryFactoryBean jobRepositoryFactoryBean = new JdbcJobRepositoryFactoryBean();
try {
jobRepositoryFactoryBean.setDataSource(getDataSource());
jobRepositoryFactoryBean.setTransactionManager(getTransactionManager());
jobRepositoryFactoryBean.setDatabaseType(getDatabaseType());
jobRepositoryFactoryBean.setIncrementerFactory(getIncrementerFactory());
jobRepositoryFactoryBean.setJobKeyGenerator(getJobKeyGenerator());
jobRepositoryFactoryBean.setClobType(getClobType());
jobRepositoryFactoryBean.setTablePrefix(getTablePrefix());
jobRepositoryFactoryBean.setSerializer(getExecutionContextSerializer());
jobRepositoryFactoryBean.setConversionService(getConversionService());
jobRepositoryFactoryBean.setJdbcOperations(getJdbcOperations());
jobRepositoryFactoryBean.setCharset(getCharset());
jobRepositoryFactoryBean.setMaxVarCharLength(getMaxVarCharLength());
jobRepositoryFactoryBean.setIsolationLevelForCreateEnum(getIsolationLevelForCreate());
jobRepositoryFactoryBean.setValidateTransactionState(getValidateTransactionState());
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
}
catch (Exception e) {
throw new BatchConfigurationException("Unable to configure the default job repository", e);
}
public JobRepository jobRepository() {
return new ResourcelessJobRepository();
}
@Bean
public JobRegistry jobRegistry() throws BatchConfigurationException {
public JobRegistry jobRegistry() {
return new MapJobRegistry();
}
/**
* Define a job operator bean.
* @param jobRepository a job repository
* @param jobRegistry a job registry
* @return a job operator
* @throws BatchConfigurationException if unable to configure the default job operator
* @since 5.2
*/
@Bean
public JobOperator jobOperator(JobRepository jobRepository, JobRegistry jobRegistry)
throws BatchConfigurationException {
@@ -175,13 +117,6 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
}
}
/**
* Define a {@link JobRegistrySmartInitializingSingleton} bean.
* @param jobRegistry the job registry to populate
* @throws BatchConfigurationException if unable to register the bean
* @return a bean of type {@link JobRegistrySmartInitializingSingleton}
* @since 5.2
*/
@Bean
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry)
throws BatchConfigurationException {
@@ -197,51 +132,34 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
}
}
/*
* Getters to customize the configuration of infrastructure beans
*/
/**
* Return the data source to use for Batch meta-data. Defaults to the bean of type
* {@link DataSource} and named "dataSource" in the application context.
* @return The data source to use for Batch meta-data
* Return the transaction manager to use for the job operator. Defaults to
* {@link ResourcelessTransactionManager}.
* @return The transaction manager to use for the job operator
*/
protected DataSource getDataSource() {
String errorMessage = " To use the default configuration, a data source bean named 'dataSource'"
+ " should be defined in the application context but none was found. Override getDataSource()"
+ " to provide the data source to use for Batch meta-data.";
if (this.applicationContext.getBeansOfType(DataSource.class).isEmpty()) {
throw new BatchConfigurationException(
"Unable to find a DataSource bean in the application context." + errorMessage);
}
else {
if (!this.applicationContext.containsBean("dataSource")) {
throw new BatchConfigurationException(errorMessage);
}
}
return this.applicationContext.getBean("dataSource", DataSource.class);
protected PlatformTransactionManager getTransactionManager() {
return new ResourcelessTransactionManager();
}
/**
* Return the transaction manager to use for the job repository. Defaults to the bean
* of type {@link PlatformTransactionManager} and named "transactionManager" in the
* application context.
* @return The transaction manager to use for the job repository
* Return the {@link TaskExecutor} to use in the job operator. Defaults to
* {@link SyncTaskExecutor}.
* @return the {@link TaskExecutor} to use in the job operator.
*/
protected PlatformTransactionManager getTransactionManager() {
String errorMessage = " To use the default configuration, a transaction manager bean named 'transactionManager'"
+ " should be defined in the application context but none was found. Override getTransactionManager()"
+ " to provide the transaction manager to use for the job repository.";
if (this.applicationContext.getBeansOfType(PlatformTransactionManager.class).isEmpty()) {
throw new BatchConfigurationException(
"Unable to find a PlatformTransactionManager bean in the application context." + errorMessage);
}
else {
if (!this.applicationContext.containsBean("transactionManager")) {
throw new BatchConfigurationException(errorMessage);
}
}
return this.applicationContext.getBean("transactionManager", PlatformTransactionManager.class);
protected TaskExecutor getTaskExecutor() {
return new SyncTaskExecutor();
}
/**
* Return the {@link JobParametersConverter} to use in the job operator. Defaults to
* {@link DefaultJobParametersConverter}
* @return the {@link JobParametersConverter} to use in the job operator.
* @deprecated since 6.0 with no replacement and scheduled for removal in 6.2 or
* later.
*/
@Deprecated(since = "6.0", forRemoval = true)
protected JobParametersConverter getJobParametersConverter() {
return new DefaultJobParametersConverter();
}
/**
@@ -262,76 +180,6 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
return Isolation.SERIALIZABLE;
}
/**
* Return the length of long string columns in database. Do not override this if you
* haven't modified the schema. Note this value will be used for the exit message in
* both {@link JdbcJobExecutionDao} and {@link JdbcStepExecutionDao} and also the
* short version of the execution context in {@link JdbcExecutionContextDao} . For
* databases with multi-byte character sets this number can be smaller (by up to a
* factor of 2 for 2-byte characters) than the declaration of the column length in the
* DDL for the tables. Defaults to
* {@link AbstractJdbcBatchMetadataDao#DEFAULT_EXIT_MESSAGE_LENGTH}
*/
protected int getMaxVarCharLength() {
return AbstractJdbcBatchMetadataDao.DEFAULT_EXIT_MESSAGE_LENGTH;
}
/**
* Return the prefix of Batch meta-data tables. Defaults to
* {@link AbstractJdbcBatchMetadataDao#DEFAULT_TABLE_PREFIX}.
* @return the prefix of meta-data tables
*/
protected String getTablePrefix() {
return AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
}
/**
* Return the {@link Charset} to use when serializing/deserializing the execution
* context. Defaults to "UTF-8".
* @return the charset to use when serializing/deserializing the execution context
*/
protected Charset getCharset() {
return StandardCharsets.UTF_8;
}
/**
* Return the {@link JdbcOperations}. If this property is not overridden, a new
* {@link JdbcTemplate} will be created for the configured data source by default.
* @return the {@link JdbcOperations} to use
*/
protected JdbcOperations getJdbcOperations() {
return new JdbcTemplate(getDataSource());
}
/**
* A custom implementation of the {@link ExecutionContextSerializer}. The default, if
* not injected, is the {@link DefaultExecutionContextSerializer}.
* @return the serializer to use to serialize/deserialize the execution context
*/
protected ExecutionContextSerializer getExecutionContextSerializer() {
return new DefaultExecutionContextSerializer();
}
/**
* Return the value from {@link java.sql.Types} class to indicate the type to use for
* a CLOB
* @return the value from {@link java.sql.Types} class to indicate the type to use for
* a CLOB
*/
protected int getClobType() {
return Types.CLOB;
}
/**
* Return the factory for creating {@link DataFieldMaxValueIncrementer}
* implementations used to increment entity IDs in meta-data tables.
* @return the factory for creating {@link DataFieldMaxValueIncrementer}
* implementations.
*/
protected DataFieldMaxValueIncrementerFactory getIncrementerFactory() {
return new DefaultDataFieldMaxValueIncrementerFactory(getDataSource());
}
/**
* A custom implementation of the {@link JobKeyGenerator}. The default, if not
* injected, is the {@link DefaultJobKeyGenerator}.
@@ -343,53 +191,4 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
return new DefaultJobKeyGenerator();
}
/**
* Return the database type. The default will be introspected from the JDBC meta-data
* of the data source.
* @return the database type
* @throws MetaDataAccessException if an error occurs when trying to get the database
* type of JDBC meta-data
*
*/
protected String getDatabaseType() throws MetaDataAccessException {
return DatabaseType.fromMetaData(getDataSource()).name();
}
/**
* Return the {@link TaskExecutor} to use in the job launcher. Defaults to
* {@link SyncTaskExecutor}.
* @return the {@link TaskExecutor} to use in the job launcher.
*/
protected TaskExecutor getTaskExecutor() {
return new SyncTaskExecutor();
}
/**
* Return the {@link JobParametersConverter} to use in the job operator. Defaults to
* {@link DefaultJobParametersConverter}
* @return the {@link JobParametersConverter} to use in the job operator.
*/
protected JobParametersConverter getJobParametersConverter() {
return new DefaultJobParametersConverter();
}
/**
* Return the conversion service to use in the job repository and job explorer. This
* service is used to convert job parameters from String literal to typed values and
* vice versa.
* @return the {@link ConfigurableConversionService} to use.
*/
protected ConfigurableConversionService getConversionService() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new DateToStringConverter());
conversionService.addConverter(new StringToDateConverter());
conversionService.addConverter(new LocalDateToStringConverter());
conversionService.addConverter(new StringToLocalDateConverter());
conversionService.addConverter(new LocalTimeToStringConverter());
conversionService.addConverter(new StringToLocalTimeConverter());
conversionService.addConverter(new LocalDateTimeToStringConverter());
conversionService.addConverter(new StringToLocalDateTimeConverter());
return conversionService;
}
}

View File

@@ -0,0 +1,262 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.configuration.support;
import org.springframework.batch.core.configuration.BatchConfigurationException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.converter.DateToStringConverter;
import org.springframework.batch.core.converter.LocalDateTimeToStringConverter;
import org.springframework.batch.core.converter.LocalDateToStringConverter;
import org.springframework.batch.core.converter.LocalTimeToStringConverter;
import org.springframework.batch.core.converter.StringToDateConverter;
import org.springframework.batch.core.converter.StringToLocalDateConverter;
import org.springframework.batch.core.converter.StringToLocalDateTimeConverter;
import org.springframework.batch.core.converter.StringToLocalTimeConverter;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
import org.springframework.batch.core.repository.dao.DefaultExecutionContextSerializer;
import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
import org.springframework.batch.core.repository.dao.JdbcStepExecutionDao;
import org.springframework.batch.core.repository.support.JdbcJobRepositoryFactoryBean;
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
import org.springframework.batch.support.DatabaseType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import javax.sql.DataSource;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Types;
/**
* Base {@link Configuration} class that provides common JDBC-based infrastructure beans
* for enabling and using Spring Batch.
* <p>
* This configuration class configures and registers the following beans in the
* application context:
*
* <ul>
* <li>a {@link JobRepository} named "jobRepository"</li>
* <li>a {@link JobRegistry} named "jobRegistry"</li>
* <li>a {@link JobOperator} named "JobOperator"</li>
* <li>a {@link JobRegistrySmartInitializingSingleton} named
* "jobRegistrySmartInitializingSingleton"</li>
* <li>a {@link org.springframework.batch.core.scope.StepScope} named "stepScope"</li>
* <li>a {@link org.springframework.batch.core.scope.JobScope} named "jobScope"</li>
* </ul>
*
* Customization is possible by extending the class and overriding getters.
* <p>
* A typical usage of this class is as follows: <pre class="code">
* &#064;Configuration
* public class MyJobConfiguration extends JdbcDefaultBatchConfiguration {
*
* &#064;Bean
* public Job job(JobRepository jobRepository) {
* return new JobBuilder("myJob", jobRepository)
* // define job flow as needed
* .build();
* }
*
* }
* </pre>
*
* @author Mahmoud Ben Hassine
* @since 6.0
*/
@Configuration(proxyBeanMethods = false)
public class JdbcDefaultBatchConfiguration extends DefaultBatchConfiguration {
@Bean
@Override
public JobRepository jobRepository() throws BatchConfigurationException {
JdbcJobRepositoryFactoryBean jobRepositoryFactoryBean = new JdbcJobRepositoryFactoryBean();
try {
jobRepositoryFactoryBean.setDataSource(getDataSource());
jobRepositoryFactoryBean.setTransactionManager(getTransactionManager());
jobRepositoryFactoryBean.setDatabaseType(getDatabaseType());
jobRepositoryFactoryBean.setIncrementerFactory(getIncrementerFactory());
jobRepositoryFactoryBean.setJobKeyGenerator(getJobKeyGenerator());
jobRepositoryFactoryBean.setClobType(getClobType());
jobRepositoryFactoryBean.setTablePrefix(getTablePrefix());
jobRepositoryFactoryBean.setSerializer(getExecutionContextSerializer());
jobRepositoryFactoryBean.setConversionService(getConversionService());
jobRepositoryFactoryBean.setJdbcOperations(getJdbcOperations());
jobRepositoryFactoryBean.setCharset(getCharset());
jobRepositoryFactoryBean.setMaxVarCharLength(getMaxVarCharLength());
jobRepositoryFactoryBean.setIsolationLevelForCreateEnum(getIsolationLevelForCreate());
jobRepositoryFactoryBean.setValidateTransactionState(getValidateTransactionState());
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
}
catch (Exception e) {
throw new BatchConfigurationException("Unable to configure the default job repository", e);
}
}
/*
* Getters to customize the configuration of infrastructure beans
*/
/**
* Return the data source to use for Batch meta-data. Defaults to the bean of type
* {@link DataSource} and named "dataSource" in the application context.
* @return The data source to use for Batch meta-data
*/
protected DataSource getDataSource() {
String errorMessage = " To use the default configuration, a data source bean named 'dataSource'"
+ " should be defined in the application context but none was found. Override getDataSource()"
+ " to provide the data source to use for Batch meta-data.";
if (this.applicationContext.getBeansOfType(DataSource.class).isEmpty()) {
throw new BatchConfigurationException(
"Unable to find a DataSource bean in the application context." + errorMessage);
}
else {
if (!this.applicationContext.containsBean("dataSource")) {
throw new BatchConfigurationException(errorMessage);
}
}
return this.applicationContext.getBean("dataSource", DataSource.class);
}
@Override
protected DataSourceTransactionManager getTransactionManager() {
String errorMessage = " To use the default configuration, a DataSourceTransactionManager bean named 'transactionManager'"
+ " should be defined in the application context but none was found. Override getTransactionManager()"
+ " to provide the transaction manager to use for the job repository.";
if (this.applicationContext.getBeansOfType(DataSourceTransactionManager.class).isEmpty()) {
throw new BatchConfigurationException(
"Unable to find a DataSourceTransactionManager bean in the application context." + errorMessage);
}
else {
if (!this.applicationContext.containsBean("transactionManager")) {
throw new BatchConfigurationException(errorMessage);
}
}
return this.applicationContext.getBean("transactionManager", DataSourceTransactionManager.class);
}
/**
* Return the length of long string columns in database. Do not override this if you
* haven't modified the schema. Note this value will be used for the exit message in
* both {@link JdbcJobExecutionDao} and {@link JdbcStepExecutionDao} and also the
* short version of the execution context in {@link JdbcExecutionContextDao} . For
* databases with multi-byte character sets this number can be smaller (by up to a
* factor of 2 for 2-byte characters) than the declaration of the column length in the
* DDL for the tables. Defaults to
* {@link AbstractJdbcBatchMetadataDao#DEFAULT_EXIT_MESSAGE_LENGTH}
*/
protected int getMaxVarCharLength() {
return AbstractJdbcBatchMetadataDao.DEFAULT_EXIT_MESSAGE_LENGTH;
}
/**
* Return the prefix of Batch meta-data tables. Defaults to
* {@link AbstractJdbcBatchMetadataDao#DEFAULT_TABLE_PREFIX}.
* @return the prefix of meta-data tables
*/
protected String getTablePrefix() {
return AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
}
/**
* Return the {@link Charset} to use when serializing/deserializing the execution
* context. Defaults to "UTF-8".
* @return the charset to use when serializing/deserializing the execution context
*/
protected Charset getCharset() {
return StandardCharsets.UTF_8;
}
/**
* Return the {@link JdbcOperations}. If this property is not overridden, a new
* {@link JdbcTemplate} will be created for the configured data source by default.
* @return the {@link JdbcOperations} to use
*/
protected JdbcOperations getJdbcOperations() {
return new JdbcTemplate(getDataSource());
}
/**
* A custom implementation of the {@link ExecutionContextSerializer}. The default, if
* not injected, is the {@link DefaultExecutionContextSerializer}.
* @return the serializer to use to serialize/deserialize the execution context
*/
protected ExecutionContextSerializer getExecutionContextSerializer() {
return new DefaultExecutionContextSerializer();
}
/**
* Return the value from {@link Types} class to indicate the type to use for a CLOB
* @return the value from {@link Types} class to indicate the type to use for a CLOB
*/
protected int getClobType() {
return Types.CLOB;
}
/**
* Return the factory for creating {@link DataFieldMaxValueIncrementer}
* implementations used to increment entity IDs in meta-data tables.
* @return the factory for creating {@link DataFieldMaxValueIncrementer}
* implementations.
*/
protected DataFieldMaxValueIncrementerFactory getIncrementerFactory() {
return new DefaultDataFieldMaxValueIncrementerFactory(getDataSource());
}
/**
* Return the database type. The default will be introspected from the JDBC meta-data
* of the data source.
* @return the database type
* @throws MetaDataAccessException if an error occurs when trying to get the database
* type of JDBC meta-data
*
*/
protected String getDatabaseType() throws MetaDataAccessException {
return DatabaseType.fromMetaData(getDataSource()).name();
}
/**
* Return the conversion service to use in the job repository and job explorer. This
* service is used to convert job parameters from String literal to typed values and
* vice versa.
* @return the {@link ConfigurableConversionService} to use.
*/
protected ConfigurableConversionService getConversionService() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new DateToStringConverter());
conversionService.addConverter(new StringToDateConverter());
conversionService.addConverter(new LocalDateToStringConverter());
conversionService.addConverter(new StringToLocalDateConverter());
conversionService.addConverter(new LocalTimeToStringConverter());
conversionService.addConverter(new StringToLocalTimeConverter());
conversionService.addConverter(new LocalDateTimeToStringConverter());
conversionService.addConverter(new StringToLocalDateTimeConverter());
return conversionService;
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.configuration.support;
import org.springframework.batch.core.configuration.BatchConfigurationException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MongoJobRepositoryFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoTransactionManager;
import org.springframework.data.mongodb.core.MongoOperations;
/**
* Base {@link Configuration} class that provides common MongoDB-based infrastructure
* beans for enabling and using Spring Batch.
* <p>
* This configuration class configures and registers the following beans in the
* application context:
*
* <ul>
* <li>a {@link JobRepository} named "jobRepository"</li>
* <li>a {@link JobRegistry} named "jobRegistry"</li>
* <li>a {@link JobOperator} named "JobOperator"</li>
* <li>a {@link JobRegistrySmartInitializingSingleton} named
* "jobRegistrySmartInitializingSingleton"</li>
* <li>a {@link org.springframework.batch.core.scope.StepScope} named "stepScope"</li>
* <li>a {@link org.springframework.batch.core.scope.JobScope} named "jobScope"</li>
* </ul>
*
* Customization is possible by extending the class and overriding getters.
* <p>
* A typical usage of this class is as follows: <pre class="code">
* &#064;Configuration
* public class MyJobConfiguration extends MongoDefaultBatchConfiguration {
*
* &#064;Bean
* public Job job(JobRepository jobRepository) {
* return new JobBuilder("myJob", jobRepository)
* // define job flow as needed
* .build();
* }
*
* }
* </pre>
*
* @author Mahmoud Ben Hassine
* @since 6.0
*/
@Configuration(proxyBeanMethods = false)
public class MongoDefaultBatchConfiguration extends DefaultBatchConfiguration {
@Bean
@Override
public JobRepository jobRepository() throws BatchConfigurationException {
MongoJobRepositoryFactoryBean jobRepositoryFactoryBean = new MongoJobRepositoryFactoryBean();
try {
jobRepositoryFactoryBean.setMongoOperations(getMongoOperations());
jobRepositoryFactoryBean.setTransactionManager(getTransactionManager());
jobRepositoryFactoryBean.setIsolationLevelForCreateEnum(getIsolationLevelForCreate());
jobRepositoryFactoryBean.setValidateTransactionState(getValidateTransactionState());
jobRepositoryFactoryBean.setJobKeyGenerator(getJobKeyGenerator());
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
}
catch (Exception e) {
throw new BatchConfigurationException("Unable to configure the default job repository", e);
}
}
/*
* Getters to customize the configuration of infrastructure beans
*/
protected MongoOperations getMongoOperations() {
String errorMessage = " To use the default configuration, a MongoOperations bean named 'mongoTemplate'"
+ " should be defined in the application context but none was found. Override getMongoOperations()"
+ " to provide the MongoOperations for Batch meta-data.";
if (this.applicationContext.getBeansOfType(MongoOperations.class).isEmpty()) {
throw new BatchConfigurationException(
"Unable to find a MongoOperations bean in the application context." + errorMessage);
}
else {
if (!this.applicationContext.containsBean("mongoTemplate")) {
throw new BatchConfigurationException(errorMessage);
}
}
return this.applicationContext.getBean("mongoTemplate", MongoOperations.class);
}
@Override
protected MongoTransactionManager getTransactionManager() {
String errorMessage = " To use the default configuration, a MongoTransactionManager bean named 'transactionManager'"
+ " should be defined in the application context but none was found. Override getTransactionManager()"
+ " to provide the transaction manager to use for the job repository.";
if (this.applicationContext.getBeansOfType(MongoTransactionManager.class).isEmpty()) {
throw new BatchConfigurationException(
"Unable to find a MongoTransactionManager bean in the application context." + errorMessage);
}
else {
if (!this.applicationContext.containsBean("transactionManager")) {
throw new BatchConfigurationException(errorMessage);
}
}
return this.applicationContext.getBean("transactionManager", MongoTransactionManager.class);
}
}

View File

@@ -57,20 +57,6 @@ import org.springframework.transaction.interceptor.TransactionInterceptor;
*/
class BatchRegistrarTests {
@Test
@DisplayName("When no datasource is provided, then an BeanCreationException should be thrown")
void testMissingDataSource() {
Assertions.assertThrows(BeanCreationException.class,
() -> new AnnotationConfigApplicationContext(JobConfigurationWithoutDataSource.class));
}
@Test
@DisplayName("When no transaction manager is provided, then an BeanCreationException should be thrown")
void testMissingTransactionManager() {
Assertions.assertThrows(BeanCreationException.class,
() -> new AnnotationConfigApplicationContext(JobConfigurationWithoutTransactionManager.class));
}
@Test
@DisplayName("When custom beans are provided, then default ones should not be used")
void testConfigurationWithUserDefinedBeans() {
@@ -227,23 +213,6 @@ class BatchRegistrarTests {
Assertions.assertEquals(JsonJobParametersConverter.class, jobParametersConverter.getClass());
}
@Configuration
@EnableBatchProcessing
public static class JobConfigurationWithoutDataSource {
}
@Configuration
@EnableBatchProcessing
public static class JobConfigurationWithoutTransactionManager {
@Bean
public DataSource dataSource() {
return Mockito.mock();
}
}
@Configuration
@EnableBatchProcessing
public static class JobConfigurationWithUserDefinedInfrastructureBeans {
@@ -277,6 +246,7 @@ class BatchRegistrarTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
public static class JobConfiguration {
@Bean
@@ -295,7 +265,8 @@ class BatchRegistrarTests {
}
@Configuration
@EnableBatchProcessing(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
@EnableBatchProcessing(transactionManagerRef = "batchTransactionManager")
@EnableJdbcJobRepository(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
public static class JobConfigurationWithCustomBeanNames {
@Bean
@@ -315,6 +286,7 @@ class BatchRegistrarTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
public static class CustomJobKeyGeneratorConfiguration {
@Bean
@@ -348,6 +320,7 @@ class BatchRegistrarTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
public static class CustomJobParametersConverterConfiguration {
@Bean

View File

@@ -64,18 +64,6 @@ class DefaultBatchConfigurationTests {
Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
@Test
void testConfigurationWithoutDataSource() {
Assertions.assertThrows(BeanCreationException.class,
() -> new AnnotationConfigApplicationContext(MyJobConfigurationWithoutDataSource.class));
}
@Test
void testConfigurationWithoutTransactionManager() {
Assertions.assertThrows(BeanCreationException.class,
() -> new AnnotationConfigApplicationContext(MyJobConfigurationWithoutTransactionManager.class));
}
@Test
void testConfigurationWithCustomInfrastructureBean() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
@@ -110,16 +98,6 @@ class DefaultBatchConfigurationTests {
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
}
@Configuration
static class MyJobConfigurationWithoutDataSource extends DefaultBatchConfiguration {
}
@Configuration
static class MyJobConfigurationWithoutTransactionManager extends DefaultBatchConfiguration {
}
@Configuration
static class MyJobConfiguration extends DefaultBatchConfiguration {

View File

@@ -189,18 +189,6 @@ class GenericApplicationContextFactoryTests {
assertThrows(IllegalArgumentException.class, factory::createApplicationContext);
}
@Test
void testPackageScanning() {
GenericApplicationContextFactory factory = new GenericApplicationContextFactory(
"org.springframework.batch.core.configuration.support");
ConfigurableApplicationContext context = factory.createApplicationContext();
assertEquals(context.getBean("bean1"), "bean1");
assertEquals(context.getBean("bean2"), "bean2");
assertEquals(context.getBean("bean3"), "bean3");
assertEquals(context.getBean("bean4"), "bean4");
}
@Test
void testMultipleConfigurationClasses() {
GenericApplicationContextFactory factory = new GenericApplicationContextFactory(Configuration1.class,

View File

@@ -34,6 +34,7 @@ import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.configuration.xml.DummyStep;
import org.springframework.batch.core.repository.explore.JobExplorer;
import org.springframework.batch.core.job.builder.JobBuilder;
@@ -81,6 +82,7 @@ class SimpleJobExplorerIntegrationTests {
*/
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class Config {
@Bean
@@ -187,6 +189,7 @@ class SimpleJobExplorerIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class JobConfiguration {
@Bean

View File

@@ -21,6 +21,7 @@ import com.ibm.db2.jcc.DB2SimpleDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.Db2Container;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -95,6 +96,7 @@ class Db2JobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -25,6 +25,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
@@ -69,6 +70,7 @@ class DerbyJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -27,6 +27,7 @@ import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
@@ -84,6 +85,7 @@ class H2CompatibilityModeJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -25,6 +25,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
@@ -69,6 +70,7 @@ class H2JobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -33,6 +33,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
@@ -112,6 +113,7 @@ class HANAJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -25,6 +25,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
@@ -69,6 +70,7 @@ class HSQLDBJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -20,6 +20,7 @@ import javax.sql.DataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mariadb.jdbc.MariaDbDataSource;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -93,6 +94,7 @@ class MariaDBJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -25,6 +25,7 @@ import javax.sql.DataSource;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -121,6 +122,7 @@ class MySQLJdbcJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -20,6 +20,7 @@ import javax.sql.DataSource;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -93,6 +94,7 @@ class MySQLJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -21,6 +21,7 @@ import oracle.jdbc.pool.OracleDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.OracleContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -101,6 +102,7 @@ class OracleJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -20,6 +20,7 @@ import javax.sql.DataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.postgresql.ds.PGSimpleDataSource;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -93,6 +94,7 @@ class PostgreSQLJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -20,6 +20,7 @@ import javax.sql.DataSource;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -94,6 +95,7 @@ class SQLServerJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -18,6 +18,7 @@ package org.springframework.batch.core.test.repository;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.sqlite.SQLiteDataSource;
import org.springframework.batch.core.ExitStatus;
@@ -70,6 +71,7 @@ class SQLiteJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
@Bean

View File

@@ -28,6 +28,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
@@ -91,6 +92,7 @@ class SybaseJobRepositoryIntegrationTests {
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
static class TestConfiguration {
// FIXME Configuration parameters are hard-coded for the moment, to update once

View File

@@ -20,6 +20,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
@@ -41,6 +42,7 @@ import org.springframework.jdbc.support.JdbcTransactionManager;
*/
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
@Import(DataSourceConfiguration.class)
public class AmqpJobConfiguration {

View File

@@ -17,7 +17,7 @@ package org.springframework.batch.samples.helloworld;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.*;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
@@ -30,6 +30,7 @@ import org.springframework.jdbc.support.JdbcTransactionManager;
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
@Import(DataSourceConfiguration.class)
public class HelloWorldJobConfiguration {

View File

@@ -20,6 +20,7 @@ import jakarta.persistence.EntityManagerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
@@ -38,6 +39,7 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.Isolation;
/**
* Hibernate JPA dialect does not support custom tx isolation levels => overwrite with
@@ -47,7 +49,8 @@ import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
*/
@Configuration
@Import(DataSourceConfiguration.class)
@EnableBatchProcessing(isolationLevelForCreate = "ISOLATION_DEFAULT", transactionManagerRef = "jpaTransactionManager")
@EnableBatchProcessing
@EnableJdbcJobRepository(isolationLevelForCreate = Isolation.DEFAULT, transactionManagerRef = "jpaTransactionManager")
public class JpaJobConfiguration {
@Bean

View File

@@ -23,6 +23,7 @@ import jakarta.persistence.EntityManagerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
@@ -45,6 +46,7 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.Isolation;
/**
* Hibernate JPA dialect does not support custom tx isolation levels => overwrite with
@@ -54,7 +56,8 @@ import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
*/
@Configuration
@Import(DataSourceConfiguration.class)
@EnableBatchProcessing(isolationLevelForCreate = "ISOLATION_DEFAULT", transactionManagerRef = "jpaTransactionManager")
@EnableBatchProcessing
@EnableJdbcJobRepository(isolationLevelForCreate = Isolation.DEFAULT, transactionManagerRef = "jpaTransactionManager")
@EnableJpaRepositories(basePackages = "org.springframework.batch.samples.jpa")
public class JpaRepositoryJobConfiguration {

View File

@@ -20,6 +20,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
@@ -42,6 +43,7 @@ import org.springframework.integration.jms.dsl.Jms;
*/
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
@EnableBatchIntegration
@Import(value = { DataSourceConfiguration.class, BrokerConfiguration.class })
public class ManagerConfiguration {

View File

@@ -19,6 +19,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
@@ -43,6 +44,7 @@ import org.springframework.transaction.PlatformTransactionManager;
*/
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
@EnableBatchIntegration
@Import(value = { DataSourceConfiguration.class, BrokerConfiguration.class })
public class WorkerConfiguration {

View File

@@ -20,6 +20,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
@@ -42,6 +43,7 @@ import org.springframework.integration.jms.dsl.Jms;
*/
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
@EnableBatchIntegration
@Import(value = { DataSourceConfiguration.class, BrokerConfiguration.class })
public class ManagerConfiguration {

View File

@@ -19,6 +19,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
@@ -43,6 +44,7 @@ import org.springframework.transaction.PlatformTransactionManager;
*/
@Configuration
@EnableBatchProcessing
@EnableJdbcJobRepository
@EnableBatchIntegration
@Import(value = { DataSourceConfiguration.class, BrokerConfiguration.class })
public class WorkerConfiguration {