Improve the process of job registration
This commit changes the way of populating the default job registry from using a BeanPostProcessor to using a JobRegistrySmartInitializingSingleton. This change resolves warnings about beans being eagerly injected into currently created BeanPostProcessors and prevents lifecycle issues about early bean initializations. It also deprecates JobRegistryBeanPostProcessor in favor of JobRegistrySmartInitializingSingleton. Resolves #4547
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -22,7 +22,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;
|
||||
import org.springframework.batch.core.configuration.support.DefaultJobLoader;
|
||||
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
|
||||
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
|
||||
import org.springframework.batch.core.configuration.support.MapJobRegistry;
|
||||
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
|
||||
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
|
||||
@@ -63,7 +63,7 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
registerJobExplorer(registry, batchAnnotation);
|
||||
registerJobLauncher(registry, batchAnnotation);
|
||||
registerJobRegistry(registry);
|
||||
registerJobRegistryBeanPostProcessor(registry);
|
||||
registerJobRegistrySmartInitializingSingleton(registry);
|
||||
registerJobOperator(registry, batchAnnotation);
|
||||
registerAutomaticJobRegistrar(registry, batchAnnotation);
|
||||
watch.stop();
|
||||
@@ -225,17 +225,19 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
registry.registerBeanDefinition("jobRegistry", beanDefinition);
|
||||
}
|
||||
|
||||
private void registerJobRegistryBeanPostProcessor(BeanDefinitionRegistry registry) {
|
||||
if (registry.containsBeanDefinition("jobRegistryBeanPostProcessor")) {
|
||||
LOGGER.info("Bean jobRegistryBeanPostProcessor already defined in the application context, skipping"
|
||||
+ " the registration of a jobRegistryBeanPostProcessor");
|
||||
private void registerJobRegistrySmartInitializingSingleton(BeanDefinitionRegistry registry) {
|
||||
if (registry.containsBeanDefinition("jobRegistrySmartInitializingSingleton")) {
|
||||
LOGGER
|
||||
.info("Bean jobRegistrySmartInitializingSingleton already defined in the application context, skipping"
|
||||
+ " the registration of a jobRegistrySmartInitializingSingleton");
|
||||
return;
|
||||
}
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(JobRegistryBeanPostProcessor.class);
|
||||
.genericBeanDefinition(JobRegistrySmartInitializingSingleton.class);
|
||||
beanDefinitionBuilder.addPropertyReference("jobRegistry", "jobRegistry");
|
||||
|
||||
registry.registerBeanDefinition("jobRegistryBeanPostProcessor", beanDefinitionBuilder.getBeanDefinition());
|
||||
registry.registerBeanDefinition("jobRegistrySmartInitializingSingleton",
|
||||
beanDefinitionBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void registerJobOperator(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@@ -93,9 +93,9 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
* "jobOperator" of type
|
||||
* {@link org.springframework.batch.core.launch.support.SimpleJobOperator})</li>
|
||||
* <li>a
|
||||
* {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor}
|
||||
* (bean name "jobRegistryBeanPostProcessor" of type
|
||||
* {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor})</li>
|
||||
* {@link org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton}
|
||||
* (bean name "jobRegistrySmartInitializingSingleton" of type
|
||||
* {@link org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton})</li>
|
||||
* </ul>
|
||||
*
|
||||
* If the configuration is specified as <code>modular=true</code>, the context also
|
||||
|
||||
@@ -251,24 +251,12 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
|
||||
* @return a {@link JobRegistryBeanPostProcessor}
|
||||
* @throws BatchConfigurationException if unable to register the bean
|
||||
* @since 5.1
|
||||
* @deprecated Use {@link #jobRegistryBeanPostProcessor(JobRegistry)} instead
|
||||
* @deprecated Use {@link #jobRegistrySmartInitializingSingleton(JobRegistry)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() throws BatchConfigurationException {
|
||||
return jobRegistryBeanPostProcessor(jobRegistry());
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a {@link JobRegistryBeanPostProcessor} bean.
|
||||
* @return a {@link JobRegistryBeanPostProcessor} bean
|
||||
* @throws BatchConfigurationException if unable to register the bean
|
||||
* @since 5.2
|
||||
*/
|
||||
@Bean
|
||||
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry)
|
||||
throws BatchConfigurationException {
|
||||
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
|
||||
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
|
||||
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry());
|
||||
try {
|
||||
jobRegistryBeanPostProcessor.afterPropertiesSet();
|
||||
return jobRegistryBeanPostProcessor;
|
||||
@@ -278,6 +266,28 @@ 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 {
|
||||
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = new JobRegistrySmartInitializingSingleton();
|
||||
jobRegistrySmartInitializingSingleton.setJobRegistry(jobRegistry);
|
||||
try {
|
||||
jobRegistrySmartInitializingSingleton.afterPropertiesSet();
|
||||
return jobRegistrySmartInitializingSingleton;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new BatchConfigurationException(
|
||||
"Unable to configure the default job registry SmartInitializingSingleton", e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Getters to customize the configuration of infrastructure beans
|
||||
*/
|
||||
|
||||
@@ -45,10 +45,13 @@ import org.springframework.util.Assert;
|
||||
* recommended in cases where this class may cause early bean initializations. You must
|
||||
* include at most one of either of them as a bean.
|
||||
*
|
||||
* @deprecated since 5.2 in favor of {@link JobRegistrySmartInitializingSingleton}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
@Deprecated(since = "5.2")
|
||||
public class JobRegistryBeanPostProcessor
|
||||
implements BeanPostProcessor, BeanFactoryAware, InitializingBean, DisposableBean {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -27,7 +27,7 @@ import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.batch.core.DefaultJobKeyGenerator;
|
||||
import org.springframework.batch.core.JobKeyGenerator;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
|
||||
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.launch.JobOperator;
|
||||
@@ -79,7 +79,7 @@ class BatchRegistrarTests {
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobLauncher.class)).isMock());
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistry.class)).isMock());
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobOperator.class)).isMock());
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistryBeanPostProcessor.class)).isMock());
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistrySmartInitializingSingleton.class)).isMock());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -162,7 +162,8 @@ class BatchRegistrarTests {
|
||||
JobExplorer jobExplorer = context.getBean(JobExplorer.class);
|
||||
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
|
||||
JobOperator jobOperator = context.getBean(JobOperator.class);
|
||||
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = context.getBean(JobRegistryBeanPostProcessor.class);
|
||||
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = context
|
||||
.getBean(JobRegistrySmartInitializingSingleton.class);
|
||||
|
||||
// then
|
||||
Assertions.assertNotNull(jobLauncher);
|
||||
@@ -170,7 +171,7 @@ class BatchRegistrarTests {
|
||||
Assertions.assertNotNull(jobExplorer);
|
||||
Assertions.assertNotNull(jobRegistry);
|
||||
Assertions.assertNotNull(jobOperator);
|
||||
Assertions.assertNotNull(jobRegistryBeanPostProcessor);
|
||||
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -249,7 +250,7 @@ class BatchRegistrarTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
|
||||
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton() {
|
||||
return Mockito.mock();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
* Copyright 2022-2024 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.
|
||||
@@ -85,9 +85,9 @@ class DefaultBatchConfigurationTests {
|
||||
Assertions.assertEquals(1, jobRepositories.size());
|
||||
JobRepository jobRepository = jobRepositories.entrySet().iterator().next().getValue();
|
||||
Assertions.assertInstanceOf(DummyJobRepository.class, jobRepository);
|
||||
Map<String, JobRegistryBeanPostProcessor> jobRegistryBeanPostProcessorMap = context
|
||||
.getBeansOfType(JobRegistryBeanPostProcessor.class);
|
||||
Assertions.assertEquals(1, jobRegistryBeanPostProcessorMap.size());
|
||||
Map<String, JobRegistrySmartInitializingSingleton> jobRegistrySmartInitializingSingletonMap = context
|
||||
.getBeansOfType(JobRegistrySmartInitializingSingleton.class);
|
||||
Assertions.assertEquals(1, jobRegistrySmartInitializingSingletonMap.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,7 +101,8 @@ class DefaultBatchConfigurationTests {
|
||||
JobExplorer jobExplorer = context.getBean(JobExplorer.class);
|
||||
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
|
||||
JobOperator jobOperator = context.getBean(JobOperator.class);
|
||||
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = context.getBean(JobRegistryBeanPostProcessor.class);
|
||||
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = context
|
||||
.getBean(JobRegistrySmartInitializingSingleton.class);
|
||||
|
||||
// then
|
||||
Assertions.assertNotNull(jobLauncher);
|
||||
@@ -109,7 +110,7 @@ class DefaultBatchConfigurationTests {
|
||||
Assertions.assertNotNull(jobExplorer);
|
||||
Assertions.assertNotNull(jobRegistry);
|
||||
Assertions.assertNotNull(jobOperator);
|
||||
Assertions.assertNotNull(jobRegistryBeanPostProcessor);
|
||||
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -161,10 +162,10 @@ class DefaultBatchConfigurationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
|
||||
JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
|
||||
postProcessor.setJobRegistry(jobRegistry);
|
||||
return postProcessor;
|
||||
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry) {
|
||||
JobRegistrySmartInitializingSingleton smartInitializingSingleton = new JobRegistrySmartInitializingSingleton();
|
||||
smartInitializingSingleton.setJobRegistry(jobRegistry);
|
||||
return smartInitializingSingleton;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -222,7 +222,12 @@ example has been given an `id` so that it can be included in child
|
||||
contexts (for example, as a parent bean definition) and cause all jobs created
|
||||
there to also be registered automatically.
|
||||
|
||||
As of version 5.1, the `@EnableBatchProcessing` annotation automatically registers a `jobRegistryBeanPostProcessor` bean in the application context.
|
||||
[WARNING]
|
||||
.Deprecation
|
||||
====
|
||||
As of version 5.2, the `JobRegistryBeanPostProcessor` class is deprecated in favor of
|
||||
`JobRegistrySmartInitializingSingleton`, see xref:#jobregistrysmartinitializingsingleton[JobRegistrySmartInitializingSingleton].
|
||||
====
|
||||
|
||||
[[jobregistrysmartinitializingsingleton]]
|
||||
=== JobRegistrySmartInitializingSingleton
|
||||
|
||||
Reference in New Issue
Block a user