Skip to content

Commit d9709ef

Browse files
committed
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
1 parent 692e769 commit d9709ef

File tree

7 files changed

+62
-40
lines changed

7 files changed

+62
-40
lines changed

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/BatchRegistrar.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
2222

2323
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;
2424
import org.springframework.batch.core.configuration.support.DefaultJobLoader;
25-
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
25+
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
2626
import org.springframework.batch.core.configuration.support.MapJobRegistry;
2727
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
2828
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
@@ -63,7 +63,7 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
6363
registerJobExplorer(registry, batchAnnotation);
6464
registerJobLauncher(registry, batchAnnotation);
6565
registerJobRegistry(registry);
66-
registerJobRegistryBeanPostProcessor(registry);
66+
registerJobRegistrySmartInitializingSingleton(registry);
6767
registerJobOperator(registry, batchAnnotation);
6868
registerAutomaticJobRegistrar(registry, batchAnnotation);
6969
watch.stop();
@@ -225,17 +225,19 @@ private void registerJobRegistry(BeanDefinitionRegistry registry) {
225225
registry.registerBeanDefinition("jobRegistry", beanDefinition);
226226
}
227227

228-
private void registerJobRegistryBeanPostProcessor(BeanDefinitionRegistry registry) {
229-
if (registry.containsBeanDefinition("jobRegistryBeanPostProcessor")) {
230-
LOGGER.info("Bean jobRegistryBeanPostProcessor already defined in the application context, skipping"
231-
+ " the registration of a jobRegistryBeanPostProcessor");
228+
private void registerJobRegistrySmartInitializingSingleton(BeanDefinitionRegistry registry) {
229+
if (registry.containsBeanDefinition("jobRegistrySmartInitializingSingleton")) {
230+
LOGGER
231+
.info("Bean jobRegistrySmartInitializingSingleton already defined in the application context, skipping"
232+
+ " the registration of a jobRegistrySmartInitializingSingleton");
232233
return;
233234
}
234235
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
235-
.genericBeanDefinition(JobRegistryBeanPostProcessor.class);
236+
.genericBeanDefinition(JobRegistrySmartInitializingSingleton.class);
236237
beanDefinitionBuilder.addPropertyReference("jobRegistry", "jobRegistry");
237238

238-
registry.registerBeanDefinition("jobRegistryBeanPostProcessor", beanDefinitionBuilder.getBeanDefinition());
239+
registry.registerBeanDefinition("jobRegistrySmartInitializingSingleton",
240+
beanDefinitionBuilder.getBeanDefinition());
239241
}
240242

241243
private void registerJobOperator(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -93,9 +93,9 @@
9393
* "jobOperator" of type
9494
* {@link org.springframework.batch.core.launch.support.SimpleJobOperator})</li>
9595
* <li>a
96-
* {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor}
97-
* (bean name "jobRegistryBeanPostProcessor" of type
98-
* {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor})</li>
96+
* {@link org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton}
97+
* (bean name "jobRegistrySmartInitializingSingleton" of type
98+
* {@link org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton})</li>
9999
* </ul>
100100
*
101101
* If the configuration is specified as <code>modular=true</code>, the context also

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -251,30 +251,40 @@ public JobOperator jobOperator(JobRepository jobRepository, JobExplorer jobExplo
251251
* @return a {@link JobRegistryBeanPostProcessor}
252252
* @throws BatchConfigurationException if unable to register the bean
253253
* @since 5.1
254-
* @deprecated Use {@link #jobRegistryBeanPostProcessor(JobRegistry)} instead
254+
* @deprecated Use {@link #jobRegistrySmartInitializingSingleton(JobRegistry)} instead
255255
*/
256256
@Deprecated(forRemoval = true)
257257
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() throws BatchConfigurationException {
258-
return jobRegistryBeanPostProcessor(jobRegistry());
258+
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
259+
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry());
260+
try {
261+
jobRegistryBeanPostProcessor.afterPropertiesSet();
262+
return jobRegistryBeanPostProcessor;
263+
}
264+
catch (Exception e) {
265+
throw new BatchConfigurationException("Unable to configure the default job registry BeanPostProcessor", e);
266+
}
259267
}
260268

261269
/**
262-
* Defines a {@link JobRegistryBeanPostProcessor} bean.
263-
* @return a {@link JobRegistryBeanPostProcessor} bean
270+
* Define a {@link JobRegistrySmartInitializingSingleton} bean.
271+
* @param jobRegistry the job registry to populate
264272
* @throws BatchConfigurationException if unable to register the bean
273+
* @return a bean of type {@link JobRegistrySmartInitializingSingleton}
265274
* @since 5.2
266275
*/
267276
@Bean
268-
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry)
277+
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry)
269278
throws BatchConfigurationException {
270-
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
271-
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
279+
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = new JobRegistrySmartInitializingSingleton();
280+
jobRegistrySmartInitializingSingleton.setJobRegistry(jobRegistry);
272281
try {
273-
jobRegistryBeanPostProcessor.afterPropertiesSet();
274-
return jobRegistryBeanPostProcessor;
282+
jobRegistrySmartInitializingSingleton.afterPropertiesSet();
283+
return jobRegistrySmartInitializingSingleton;
275284
}
276285
catch (Exception e) {
277-
throw new BatchConfigurationException("Unable to configure the default job registry BeanPostProcessor", e);
286+
throw new BatchConfigurationException(
287+
"Unable to configure the default job registry SmartInitializingSingleton", e);
278288
}
279289
}
280290

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistryBeanPostProcessor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@
4545
* recommended in cases where this class may cause early bean initializations. You must
4646
* include at most one of either of them as a bean.
4747
*
48+
* @deprecated since 5.2 in favor of {@link JobRegistrySmartInitializingSingleton}.
49+
*
4850
* @author Dave Syer
4951
* @author Mahmoud Ben Hassine
5052
*
5153
*/
54+
@Deprecated(since = "5.2")
5255
public class JobRegistryBeanPostProcessor
5356
implements BeanPostProcessor, BeanFactoryAware, InitializingBean, DisposableBean {
5457

spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/BatchRegistrarTests.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
2727
import org.springframework.batch.core.DefaultJobKeyGenerator;
2828
import org.springframework.batch.core.JobKeyGenerator;
2929
import org.springframework.batch.core.configuration.JobRegistry;
30-
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
30+
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
3131
import org.springframework.batch.core.explore.JobExplorer;
3232
import org.springframework.batch.core.launch.JobLauncher;
3333
import org.springframework.batch.core.launch.JobOperator;
@@ -79,7 +79,7 @@ void testConfigurationWithUserDefinedBeans() {
7979
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobLauncher.class)).isMock());
8080
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistry.class)).isMock());
8181
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobOperator.class)).isMock());
82-
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistryBeanPostProcessor.class)).isMock());
82+
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistrySmartInitializingSingleton.class)).isMock());
8383
}
8484

8585
@Test
@@ -162,15 +162,16 @@ void testDefaultInfrastructureBeansRegistration() {
162162
JobExplorer jobExplorer = context.getBean(JobExplorer.class);
163163
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
164164
JobOperator jobOperator = context.getBean(JobOperator.class);
165-
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = context.getBean(JobRegistryBeanPostProcessor.class);
165+
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = context
166+
.getBean(JobRegistrySmartInitializingSingleton.class);
166167

167168
// then
168169
Assertions.assertNotNull(jobLauncher);
169170
Assertions.assertNotNull(jobRepository);
170171
Assertions.assertNotNull(jobExplorer);
171172
Assertions.assertNotNull(jobRegistry);
172173
Assertions.assertNotNull(jobOperator);
173-
Assertions.assertNotNull(jobRegistryBeanPostProcessor);
174+
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
174175
}
175176

176177
@Test
@@ -249,7 +250,7 @@ public JobOperator jobOperator() {
249250
}
250251

251252
@Bean
252-
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
253+
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton() {
253254
return Mockito.mock();
254255
}
255256

spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/DefaultBatchConfigurationTests.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -85,9 +85,9 @@ void testConfigurationWithCustomInfrastructureBean() {
8585
Assertions.assertEquals(1, jobRepositories.size());
8686
JobRepository jobRepository = jobRepositories.entrySet().iterator().next().getValue();
8787
Assertions.assertInstanceOf(DummyJobRepository.class, jobRepository);
88-
Map<String, JobRegistryBeanPostProcessor> jobRegistryBeanPostProcessorMap = context
89-
.getBeansOfType(JobRegistryBeanPostProcessor.class);
90-
Assertions.assertEquals(1, jobRegistryBeanPostProcessorMap.size());
88+
Map<String, JobRegistrySmartInitializingSingleton> jobRegistrySmartInitializingSingletonMap = context
89+
.getBeansOfType(JobRegistrySmartInitializingSingleton.class);
90+
Assertions.assertEquals(1, jobRegistrySmartInitializingSingletonMap.size());
9191
}
9292

9393
@Test
@@ -101,15 +101,16 @@ void testDefaultInfrastructureBeansRegistration() {
101101
JobExplorer jobExplorer = context.getBean(JobExplorer.class);
102102
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
103103
JobOperator jobOperator = context.getBean(JobOperator.class);
104-
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = context.getBean(JobRegistryBeanPostProcessor.class);
104+
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = context
105+
.getBean(JobRegistrySmartInitializingSingleton.class);
105106

106107
// then
107108
Assertions.assertNotNull(jobLauncher);
108109
Assertions.assertNotNull(jobRepository);
109110
Assertions.assertNotNull(jobExplorer);
110111
Assertions.assertNotNull(jobRegistry);
111112
Assertions.assertNotNull(jobOperator);
112-
Assertions.assertNotNull(jobRegistryBeanPostProcessor);
113+
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
113114
}
114115

115116
@Configuration
@@ -161,10 +162,10 @@ public JobRepository jobRepository() {
161162
}
162163

163164
@Bean
164-
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
165-
JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
166-
postProcessor.setJobRegistry(jobRegistry);
167-
return postProcessor;
165+
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry) {
166+
JobRegistrySmartInitializingSingleton smartInitializingSingleton = new JobRegistrySmartInitializingSingleton();
167+
smartInitializingSingleton.setJobRegistry(jobRegistry);
168+
return smartInitializingSingleton;
168169
}
169170

170171
}

spring-batch-docs/modules/ROOT/pages/job/advanced-meta-data.adoc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,12 @@ example has been given an `id` so that it can be included in child
222222
contexts (for example, as a parent bean definition) and cause all jobs created
223223
there to also be registered automatically.
224224

225-
As of version 5.1, the `@EnableBatchProcessing` annotation automatically registers a `jobRegistryBeanPostProcessor` bean in the application context.
225+
[WARNING]
226+
.Deprecation
227+
====
228+
As of version 5.2, the `JobRegistryBeanPostProcessor` class is deprecated in favor of
229+
`JobRegistrySmartInitializingSingleton`, see xref:#jobregistrysmartinitializingsingleton[JobRegistrySmartInitializingSingleton].
230+
====
226231

227232
[[jobregistrysmartinitializingsingleton]]
228233
=== JobRegistrySmartInitializingSingleton

0 commit comments

Comments
 (0)