Skip to content

Commit 66e0b9a

Browse files
committed
Register a JobOperator and a JobRegistryBPP with the default configuration
This commit registers a `SimpleJobOperator` with the default batch configuration through `EnableBatchProcessing` and `DefaultBatchConfiguration`. It also registers a `JobRegistryBeanPostProcessor` to automatically populate the registry with user defined jobs. Resolves #3941
1 parent 171a3c8 commit 66e0b9a

File tree

5 files changed

+132
-1
lines changed

5 files changed

+132
-1
lines changed

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
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;
2526
import org.springframework.batch.core.configuration.support.MapJobRegistry;
2627
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
28+
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
2729
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
2830
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
2931
import org.springframework.beans.factory.config.BeanDefinition;
@@ -60,6 +62,8 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
6062
registerJobExplorer(registry, batchAnnotation, importingClassName);
6163
registerJobLauncher(registry, batchAnnotation, importingClassName);
6264
registerJobRegistry(registry);
65+
registerJobRegistryBeanPostProcessor(registry);
66+
registerJobOperator(registry, batchAnnotation);
6367
registerAutomaticJobRegistrar(registry, batchAnnotation);
6468
watch.stop();
6569
LOGGER.info(LogMessage.format("Finished Spring Batch infrastrucutre beans configuration in %s ms.",
@@ -208,6 +212,39 @@ private void registerJobRegistry(BeanDefinitionRegistry registry) {
208212
registry.registerBeanDefinition("jobRegistry", beanDefinition);
209213
}
210214

215+
private void registerJobRegistryBeanPostProcessor(BeanDefinitionRegistry registry) {
216+
if (registry.containsBeanDefinition("jobRegistryBeanPostProcessor")) {
217+
LOGGER.info("Bean jobRegistryBeanPostProcessor already defined in the application context, skipping"
218+
+ " the registration of a jobRegistryBeanPostProcessor");
219+
return;
220+
}
221+
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
222+
.genericBeanDefinition(JobRegistryBeanPostProcessor.class);
223+
beanDefinitionBuilder.addPropertyReference("jobRegistry", "jobRegistry");
224+
225+
registry.registerBeanDefinition("jobRegistryBeanPostProcessor", beanDefinitionBuilder.getBeanDefinition());
226+
}
227+
228+
private void registerJobOperator(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
229+
if (registry.containsBeanDefinition("jobOperator")) {
230+
LOGGER.info("Bean jobOperator already defined in the application context, skipping"
231+
+ " the registration of a jobOperator");
232+
return;
233+
}
234+
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
235+
.genericBeanDefinition(JobOperatorFactoryBean.class);
236+
// set mandatory properties
237+
String transactionManagerRef = batchAnnotation.transactionManagerRef();
238+
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
239+
240+
beanDefinitionBuilder.addPropertyReference("jobRepository", "jobRepository");
241+
beanDefinitionBuilder.addPropertyReference("jobLauncher", "jobLauncher");
242+
beanDefinitionBuilder.addPropertyReference("jobExplorer", "jobExplorer");
243+
beanDefinitionBuilder.addPropertyReference("jobRegistry", "jobRegistry");
244+
245+
registry.registerBeanDefinition("jobOperator", beanDefinitionBuilder.getBeanDefinition());
246+
}
247+
211248
private void registerAutomaticJobRegistrar(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
212249
if (!batchAnnotation.modular()) {
213250
return;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@
8888
* <li>a {@link org.springframework.batch.core.explore.JobExplorer} (bean name
8989
* "jobExplorer" of type
9090
* {@link org.springframework.batch.core.explore.support.SimpleJobExplorer})</li>
91+
* <li>a {@link org.springframework.batch.core.launch.JobOperator} (bean name
92+
* "jobOperator" of type
93+
* {@link org.springframework.batch.core.launch.support.SimpleJobOperator})</li>
94+
* <li>a
95+
* {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor}
96+
* (bean name "jobRegistryBeanPostProcessor" of type
97+
* {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor})</li>
9198
* </ul>
9299
*
93100
* 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: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import org.springframework.batch.core.explore.JobExplorer;
3030
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
3131
import org.springframework.batch.core.launch.JobLauncher;
32+
import org.springframework.batch.core.launch.JobOperator;
33+
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
3234
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
3335
import org.springframework.batch.core.repository.ExecutionContextSerializer;
3436
import org.springframework.batch.core.repository.JobRepository;
@@ -73,6 +75,8 @@
7375
* <li>a {@link JobExplorer} named "jobExplorer"</li>
7476
* <li>a {@link JobLauncher} named "jobLauncher"</li>
7577
* <li>a {@link JobRegistry} named "jobRegistry"</li>
78+
* <li>a {@link JobOperator} named "JobOperator"</li>
79+
* <li>a {@link JobRegistryBeanPostProcessor} named "jobRegistryBeanPostProcessor"</li>
7680
* <li>a {@link org.springframework.batch.core.scope.StepScope} named "stepScope"</li>
7781
* <li>a {@link org.springframework.batch.core.scope.JobScope} named "jobScope"</li>
7882
* </ul>
@@ -177,10 +181,40 @@ public JobExplorer jobExplorer() throws BatchConfigurationException {
177181
}
178182

179183
@Bean
180-
public JobRegistry jobRegistry() throws Exception {
184+
public JobRegistry jobRegistry() throws BatchConfigurationException {
181185
return this.jobRegistry; // FIXME returning a new instance here does not work
182186
}
183187

188+
@Bean
189+
public JobOperator jobOperator() throws BatchConfigurationException {
190+
JobOperatorFactoryBean jobOperatorFactoryBean = new JobOperatorFactoryBean();
191+
jobOperatorFactoryBean.setTransactionManager(getTransactionManager());
192+
jobOperatorFactoryBean.setJobRepository(jobRepository());
193+
jobOperatorFactoryBean.setJobExplorer(jobExplorer());
194+
jobOperatorFactoryBean.setJobRegistry(jobRegistry());
195+
jobOperatorFactoryBean.setJobLauncher(jobLauncher());
196+
try {
197+
jobOperatorFactoryBean.afterPropertiesSet();
198+
return jobOperatorFactoryBean.getObject();
199+
}
200+
catch (Exception e) {
201+
throw new BatchConfigurationException("Unable to configure the default job operator", e);
202+
}
203+
}
204+
205+
@Bean
206+
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() throws BatchConfigurationException {
207+
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
208+
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry());
209+
try {
210+
jobRegistryBeanPostProcessor.afterPropertiesSet();
211+
return jobRegistryBeanPostProcessor;
212+
}
213+
catch (Exception e) {
214+
throw new BatchConfigurationException("Unable to configure the default job registry BeanPostProcessor", e);
215+
}
216+
}
217+
184218
/*
185219
* Getters to customize the configuration of infrastructure beans
186220
*/

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.batch.core.configuration.JobRegistry;
2929
import org.springframework.batch.core.explore.JobExplorer;
3030
import org.springframework.batch.core.launch.JobLauncher;
31+
import org.springframework.batch.core.launch.JobOperator;
3132
import org.springframework.batch.core.repository.JobRepository;
3233
import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
3334
import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
@@ -88,6 +89,8 @@ void testConfigurationWithUserDefinedBeans() {
8889
context.getBean(JobLauncher.class));
8990
Assertions.assertEquals(JobConfigurationWithUserDefinedInfrastrucutreBeans.jobRegistry,
9091
context.getBean(JobRegistry.class));
92+
Assertions.assertEquals(JobConfigurationWithUserDefinedInfrastrucutreBeans.jobOperator,
93+
context.getBean(JobOperator.class));
9194
}
9295

9396
@Test
@@ -159,6 +162,26 @@ void testConfigurationWithCustonBeanNames() {
159162
Assertions.assertEquals(context.getBean(JdbcTransactionManager.class), transactionManager);
160163
}
161164

165+
@Test
166+
void testDefaultInfrastructureBeansRegistration() {
167+
// given
168+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JobConfiguration.class);
169+
170+
// when
171+
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
172+
JobRepository jobRepository = context.getBean(JobRepository.class);
173+
JobExplorer jobExplorer = context.getBean(JobExplorer.class);
174+
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
175+
JobOperator jobOperator = context.getBean(JobOperator.class);
176+
177+
// then
178+
Assertions.assertNotNull(jobLauncher);
179+
Assertions.assertNotNull(jobRepository);
180+
Assertions.assertNotNull(jobExplorer);
181+
Assertions.assertNotNull(jobRegistry);
182+
Assertions.assertNotNull(jobOperator);
183+
}
184+
162185
@Configuration
163186
@EnableBatchProcessing
164187
public static class JobConfigurationWithoutDataSource {
@@ -188,6 +211,8 @@ public static class JobConfigurationWithUserDefinedInfrastrucutreBeans {
188211

189212
public static JobRegistry jobRegistry = Mockito.mock(JobRegistry.class);
190213

214+
public static JobOperator jobOperator = Mockito.mock(JobOperator.class);
215+
191216
@Bean
192217
public JobRepository jobRepository() {
193218
return jobRepository;
@@ -208,6 +233,11 @@ public JobRegistry jobRegistry() {
208233
return jobRegistry;
209234
}
210235

236+
@Bean
237+
public JobOperator jobOperator() {
238+
return jobOperator;
239+
}
240+
211241
}
212242

213243
@Configuration

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@
2828
import org.springframework.batch.core.JobExecution;
2929
import org.springframework.batch.core.JobParameters;
3030
import org.springframework.batch.core.Step;
31+
import org.springframework.batch.core.configuration.JobRegistry;
3132
import org.springframework.batch.core.configuration.xml.DummyJobRepository;
33+
import org.springframework.batch.core.explore.JobExplorer;
3234
import org.springframework.batch.core.job.builder.JobBuilder;
3335
import org.springframework.batch.core.launch.JobLauncher;
36+
import org.springframework.batch.core.launch.JobOperator;
3437
import org.springframework.batch.core.repository.JobRepository;
3538
import org.springframework.batch.core.step.builder.StepBuilder;
3639
import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -93,6 +96,26 @@ void testConfigurationWithCustomInfrastructureBean() {
9396
Assertions.assertInstanceOf(DummyJobRepository.class, jobRepository);
9497
}
9598

99+
@Test
100+
void testDefaultInfrastructureBeansRegistration() {
101+
// given
102+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyJobConfiguration.class);
103+
104+
// when
105+
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
106+
JobRepository jobRepository = context.getBean(JobRepository.class);
107+
JobExplorer jobExplorer = context.getBean(JobExplorer.class);
108+
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
109+
JobOperator jobOperator = context.getBean(JobOperator.class);
110+
111+
// then
112+
Assertions.assertNotNull(jobLauncher);
113+
Assertions.assertNotNull(jobRepository);
114+
Assertions.assertNotNull(jobExplorer);
115+
Assertions.assertNotNull(jobRegistry);
116+
Assertions.assertNotNull(jobOperator);
117+
}
118+
96119
@Configuration
97120
static class MyJobConfigurationWithoutDataSource extends DefaultBatchConfiguration {
98121

0 commit comments

Comments
 (0)