Remove bean reference checks in BatchRegistrar

These checks occur too early in the bean creation/registration
process and might cause issues when initializing the context.

Related to #3942
This commit is contained in:
Mahmoud Ben Hassine
2022-09-20 15:35:31 +02:00
parent 48e437ae17
commit aaf22e1860
2 changed files with 81 additions and 32 deletions

View File

@@ -46,8 +46,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
private static final Log LOGGER = LogFactory.getLog(BatchRegistrar.class);
private static final String MISSING_BEAN_ERROR_MESSAGE = "Unable to find bean '%s' for attribute %s of annotation %s on class %s";
private static final String MISSING_ANNOTATION_ERROR_MESSAGE = "EnableBatchProcessing is not present on importing class '%s' as expected";
@Override
@@ -88,24 +86,10 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
// set mandatory properties
String dataSourceRef = batchAnnotation.dataSourceRef();
if (!registry.containsBeanDefinition(dataSourceRef)) {
String errorMessage = String.format(MISSING_BEAN_ERROR_MESSAGE, dataSourceRef, "dataSourceRef",
batchAnnotation, importingClassName);
throw new IllegalStateException(errorMessage);
}
else {
beanDefinitionBuilder.addPropertyReference("dataSource", dataSourceRef);
}
beanDefinitionBuilder.addPropertyReference("dataSource", dataSourceRef);
String transactionManagerRef = batchAnnotation.transactionManagerRef();
if (!registry.containsBeanDefinition(transactionManagerRef)) {
String errorMessage = String.format(MISSING_BEAN_ERROR_MESSAGE, transactionManagerRef,
"transactionManagerRef", batchAnnotation, importingClassName);
throw new IllegalStateException(errorMessage);
}
else {
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
}
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
// set optional properties
String executionContextSerializerRef = batchAnnotation.executionContextSerializerRef();
@@ -150,14 +134,7 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
// set mandatory properties
String dataSourceRef = batchAnnotation.dataSourceRef();
if (!registry.containsBeanDefinition(dataSourceRef)) {
String errorMessage = String.format(MISSING_BEAN_ERROR_MESSAGE, dataSourceRef, "dataSourceRef",
batchAnnotation, importingClassName);
throw new IllegalStateException(errorMessage);
}
else {
beanDefinitionBuilder.addPropertyReference("dataSource", dataSourceRef);
}
beanDefinitionBuilder.addPropertyReference("dataSource", dataSourceRef);
// set optional properties
String executionContextSerializerRef = batchAnnotation.executionContextSerializerRef();

View File

@@ -29,7 +29,11 @@ import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
import org.springframework.batch.core.repository.dao.JdbcJobInstanceDao;
import org.springframework.batch.core.repository.dao.JdbcStepExecutionDao;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -49,9 +53,9 @@ import org.springframework.transaction.interceptor.TransactionInterceptor;
class BatchRegistrarTests {
@Test
@DisplayName("When no datasource is provided, then an IllegalStateException should be thrown")
@DisplayName("When no datasource is provided, then an BeanCreationException should be thrown")
void testMissingDataSource() {
Assertions.assertThrows(IllegalStateException.class, new Executable() {
Assertions.assertThrows(BeanCreationException.class, new Executable() {
@Override
public void execute() throws Throwable {
new AnnotationConfigApplicationContext(JobConfigurationWithoutDataSource.class);
@@ -60,9 +64,9 @@ class BatchRegistrarTests {
}
@Test
@DisplayName("When no transaction manager is provided, then an IllegalStateException should be thrown")
@DisplayName("When no transaction manager is provided, then an BeanCreationException should be thrown")
void testMissingTransactionManager() {
Assertions.assertThrows(IllegalStateException.class, new Executable() {
Assertions.assertThrows(BeanCreationException.class, new Executable() {
@Override
public void execute() throws Throwable {
new AnnotationConfigApplicationContext(JobConfigurationWithoutTransactionManager.class);
@@ -71,7 +75,7 @@ class BatchRegistrarTests {
}
@Test
@DisplayName("When cusotm beans are provided, then no new ones should be created")
@DisplayName("When cusotm beans are provided, then default ones should not be used")
void testConfigurationWithUserDefinedBeans() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
JobConfigurationWithUserDefinedInfrastrucutreBeans.class);
@@ -98,7 +102,58 @@ class BatchRegistrarTests {
DataSource dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
// TODO assert on other DAOs
JdbcJobExecutionDao jobExecutionDao = (JdbcJobExecutionDao) ReflectionTestUtils.getField(jobRepository,
"jobExecutionDao");
jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(jobExecutionDao, "jdbcTemplate");
dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
JdbcStepExecutionDao stepExecutionDao = (JdbcStepExecutionDao) ReflectionTestUtils.getField(jobRepository,
"stepExecutionDao");
jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(stepExecutionDao, "jdbcTemplate");
dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
JdbcExecutionContextDao executionContextDao = (JdbcExecutionContextDao) ReflectionTestUtils
.getField(jobRepository, "ecDao");
jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(executionContextDao, "jdbcTemplate");
dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
PlatformTransactionManager transactionManager = getTransactionManagerSetOnJobRepository(jobRepository);
Assertions.assertEquals(context.getBean(JdbcTransactionManager.class), transactionManager);
}
@Test
@DisplayName("When custom bean names are provided, then corresponding beans should be used to configure infrastructure beans")
void testConfigurationWithCustonBeanNames() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
JobConfigurationWithCustomBeanNames.class);
JobRepository jobRepository = context.getBean(JobRepository.class);
JdbcJobInstanceDao jobInstanceDao = (JdbcJobInstanceDao) ReflectionTestUtils.getField(jobRepository,
"jobInstanceDao");
JdbcTemplate jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(jobInstanceDao, "jdbcTemplate");
DataSource dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
JdbcJobExecutionDao jobExecutionDao = (JdbcJobExecutionDao) ReflectionTestUtils.getField(jobRepository,
"jobExecutionDao");
jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(jobExecutionDao, "jdbcTemplate");
dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
JdbcStepExecutionDao stepExecutionDao = (JdbcStepExecutionDao) ReflectionTestUtils.getField(jobRepository,
"stepExecutionDao");
jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(stepExecutionDao, "jdbcTemplate");
dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
JdbcExecutionContextDao executionContextDao = (JdbcExecutionContextDao) ReflectionTestUtils
.getField(jobRepository, "ecDao");
jdbcTemplate = (JdbcTemplate) ReflectionTestUtils.getField(executionContextDao, "jdbcTemplate");
dataSource = (DataSource) ReflectionTestUtils.getField(jdbcTemplate, "dataSource");
Assertions.assertEquals(context.getBean(DataSource.class), dataSource);
PlatformTransactionManager transactionManager = getTransactionManagerSetOnJobRepository(jobRepository);
Assertions.assertEquals(context.getBean(JdbcTransactionManager.class), transactionManager);
@@ -172,6 +227,23 @@ class BatchRegistrarTests {
}
@Configuration
@EnableBatchProcessing(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
public static class JobConfigurationWithCustomBeanNames {
@Bean
public DataSource batchDataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("/org/springframework/batch/core/schema-hsqldb.sql").generateUniqueName(true).build();
}
@Bean
public JdbcTransactionManager batchTransactionManager(DataSource dataSource) {
return new JdbcTransactionManager(dataSource);
}
}
private PlatformTransactionManager getTransactionManagerSetOnJobRepository(JobRepository jobRepository) {
Advised target = (Advised) jobRepository; // proxy created by
// AbstractJobRepositoryFactoryBean