diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/BatchRegistrar.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/BatchRegistrar.java
index f8b3fef27..028cf53b3 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/BatchRegistrar.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/BatchRegistrar.java
@@ -22,8 +22,10 @@ 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.MapJobRegistry;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
+import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -60,6 +62,8 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
registerJobExplorer(registry, batchAnnotation, importingClassName);
registerJobLauncher(registry, batchAnnotation, importingClassName);
registerJobRegistry(registry);
+ registerJobRegistryBeanPostProcessor(registry);
+ registerJobOperator(registry, batchAnnotation);
registerAutomaticJobRegistrar(registry, batchAnnotation);
watch.stop();
LOGGER.info(LogMessage.format("Finished Spring Batch infrastrucutre beans configuration in %s ms.",
@@ -208,6 +212,39 @@ 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");
+ return;
+ }
+ BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(JobRegistryBeanPostProcessor.class);
+ beanDefinitionBuilder.addPropertyReference("jobRegistry", "jobRegistry");
+
+ registry.registerBeanDefinition("jobRegistryBeanPostProcessor", beanDefinitionBuilder.getBeanDefinition());
+ }
+
+ private void registerJobOperator(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
+ if (registry.containsBeanDefinition("jobOperator")) {
+ LOGGER.info("Bean jobOperator already defined in the application context, skipping"
+ + " the registration of a jobOperator");
+ return;
+ }
+ BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(JobOperatorFactoryBean.class);
+ // set mandatory properties
+ String transactionManagerRef = batchAnnotation.transactionManagerRef();
+ beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
+
+ beanDefinitionBuilder.addPropertyReference("jobRepository", "jobRepository");
+ beanDefinitionBuilder.addPropertyReference("jobLauncher", "jobLauncher");
+ beanDefinitionBuilder.addPropertyReference("jobExplorer", "jobExplorer");
+ beanDefinitionBuilder.addPropertyReference("jobRegistry", "jobRegistry");
+
+ registry.registerBeanDefinition("jobOperator", beanDefinitionBuilder.getBeanDefinition());
+ }
+
private void registerAutomaticJobRegistrar(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
if (!batchAnnotation.modular()) {
return;
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java
index ac28ad33b..e11e0a8f0 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java
@@ -88,6 +88,13 @@ import org.springframework.context.annotation.Import;
*
a {@link org.springframework.batch.core.explore.JobExplorer} (bean name
* "jobExplorer" of type
* {@link org.springframework.batch.core.explore.support.SimpleJobExplorer})
+ * a {@link org.springframework.batch.core.launch.JobOperator} (bean name
+ * "jobOperator" of type
+ * {@link org.springframework.batch.core.launch.support.SimpleJobOperator})
+ * a
+ * {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor}
+ * (bean name "jobRegistryBeanPostProcessor" of type
+ * {@link org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor})
*
*
* If the configuration is specified as modular=true, the context also
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java
index 0d85e6efa..ef74ed607 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java
@@ -29,6 +29,8 @@ import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
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.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.JobRepository;
@@ -73,6 +75,8 @@ import org.springframework.transaction.annotation.Isolation;
* a {@link JobExplorer} named "jobExplorer"
* a {@link JobLauncher} named "jobLauncher"
* a {@link JobRegistry} named "jobRegistry"
+ * a {@link JobOperator} named "JobOperator"
+ * a {@link JobRegistryBeanPostProcessor} named "jobRegistryBeanPostProcessor"
* a {@link org.springframework.batch.core.scope.StepScope} named "stepScope"
* a {@link org.springframework.batch.core.scope.JobScope} named "jobScope"
*
@@ -177,10 +181,40 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
}
@Bean
- public JobRegistry jobRegistry() throws Exception {
+ public JobRegistry jobRegistry() throws BatchConfigurationException {
return this.jobRegistry; // FIXME returning a new instance here does not work
}
+ @Bean
+ public JobOperator jobOperator() throws BatchConfigurationException {
+ JobOperatorFactoryBean jobOperatorFactoryBean = new JobOperatorFactoryBean();
+ jobOperatorFactoryBean.setTransactionManager(getTransactionManager());
+ jobOperatorFactoryBean.setJobRepository(jobRepository());
+ jobOperatorFactoryBean.setJobExplorer(jobExplorer());
+ jobOperatorFactoryBean.setJobRegistry(jobRegistry());
+ jobOperatorFactoryBean.setJobLauncher(jobLauncher());
+ try {
+ jobOperatorFactoryBean.afterPropertiesSet();
+ return jobOperatorFactoryBean.getObject();
+ }
+ catch (Exception e) {
+ throw new BatchConfigurationException("Unable to configure the default job operator", e);
+ }
+ }
+
+ @Bean
+ public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() throws BatchConfigurationException {
+ JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
+ jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry());
+ try {
+ jobRegistryBeanPostProcessor.afterPropertiesSet();
+ return jobRegistryBeanPostProcessor;
+ }
+ catch (Exception e) {
+ throw new BatchConfigurationException("Unable to configure the default job registry BeanPostProcessor", e);
+ }
+ }
+
/*
* Getters to customize the configuration of infrastructure beans
*/
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/BatchRegistrarTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/BatchRegistrarTests.java
index 1b42ef4f1..fd15239ca 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/BatchRegistrarTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/BatchRegistrarTests.java
@@ -28,6 +28,7 @@ import org.springframework.aop.framework.Advised;
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.launch.JobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
@@ -88,6 +89,8 @@ class BatchRegistrarTests {
context.getBean(JobLauncher.class));
Assertions.assertEquals(JobConfigurationWithUserDefinedInfrastrucutreBeans.jobRegistry,
context.getBean(JobRegistry.class));
+ Assertions.assertEquals(JobConfigurationWithUserDefinedInfrastrucutreBeans.jobOperator,
+ context.getBean(JobOperator.class));
}
@Test
@@ -159,6 +162,26 @@ class BatchRegistrarTests {
Assertions.assertEquals(context.getBean(JdbcTransactionManager.class), transactionManager);
}
+ @Test
+ void testDefaultInfrastructureBeansRegistration() {
+ // given
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JobConfiguration.class);
+
+ // when
+ JobLauncher jobLauncher = context.getBean(JobLauncher.class);
+ JobRepository jobRepository = context.getBean(JobRepository.class);
+ JobExplorer jobExplorer = context.getBean(JobExplorer.class);
+ JobRegistry jobRegistry = context.getBean(JobRegistry.class);
+ JobOperator jobOperator = context.getBean(JobOperator.class);
+
+ // then
+ Assertions.assertNotNull(jobLauncher);
+ Assertions.assertNotNull(jobRepository);
+ Assertions.assertNotNull(jobExplorer);
+ Assertions.assertNotNull(jobRegistry);
+ Assertions.assertNotNull(jobOperator);
+ }
+
@Configuration
@EnableBatchProcessing
public static class JobConfigurationWithoutDataSource {
@@ -188,6 +211,8 @@ class BatchRegistrarTests {
public static JobRegistry jobRegistry = Mockito.mock(JobRegistry.class);
+ public static JobOperator jobOperator = Mockito.mock(JobOperator.class);
+
@Bean
public JobRepository jobRepository() {
return jobRepository;
@@ -208,6 +233,11 @@ class BatchRegistrarTests {
return jobRegistry;
}
+ @Bean
+ public JobOperator jobOperator() {
+ return jobOperator;
+ }
+
}
@Configuration
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/DefaultBatchConfigurationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/DefaultBatchConfigurationTests.java
index 76f0b20ae..7815891e1 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/DefaultBatchConfigurationTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/DefaultBatchConfigurationTests.java
@@ -28,9 +28,12 @@ import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
+import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.xml.DummyJobRepository;
+import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -93,6 +96,26 @@ class DefaultBatchConfigurationTests {
Assertions.assertInstanceOf(DummyJobRepository.class, jobRepository);
}
+ @Test
+ void testDefaultInfrastructureBeansRegistration() {
+ // given
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyJobConfiguration.class);
+
+ // when
+ JobLauncher jobLauncher = context.getBean(JobLauncher.class);
+ JobRepository jobRepository = context.getBean(JobRepository.class);
+ JobExplorer jobExplorer = context.getBean(JobExplorer.class);
+ JobRegistry jobRegistry = context.getBean(JobRegistry.class);
+ JobOperator jobOperator = context.getBean(JobOperator.class);
+
+ // then
+ Assertions.assertNotNull(jobLauncher);
+ Assertions.assertNotNull(jobRepository);
+ Assertions.assertNotNull(jobExplorer);
+ Assertions.assertNotNull(jobRegistry);
+ Assertions.assertNotNull(jobOperator);
+ }
+
@Configuration
static class MyJobConfigurationWithoutDataSource extends DefaultBatchConfiguration {