Skip to content

Commit 31f4325

Browse files
committed
Supports modularizing job configuration like @EnableBatchProcessing(modular=true)
1 parent cc23029 commit 31f4325

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,16 @@
2020

2121
import javax.sql.DataSource;
2222

23+
import org.springframework.batch.core.configuration.BatchConfigurationException;
24+
import org.springframework.batch.core.configuration.JobRegistry;
2325
import org.springframework.batch.core.configuration.ListableJobLocator;
26+
import org.springframework.batch.core.configuration.StepRegistry;
2427
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
28+
import org.springframework.batch.core.configuration.support.ApplicationContextFactory;
29+
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;
2530
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
31+
import org.springframework.batch.core.configuration.support.DefaultJobLoader;
32+
import org.springframework.batch.core.configuration.support.JobLoader;
2633
import org.springframework.batch.core.converter.JobParametersConverter;
2734
import org.springframework.batch.core.explore.JobExplorer;
2835
import org.springframework.batch.core.launch.JobLauncher;
@@ -66,6 +73,7 @@
6673
* @author Eddú Meléndez
6774
* @author Kazuki Shimizu
6875
* @author Mahmoud Ben Hassine
76+
* @author Yanming Zhou
6977
* @since 1.0.0
7078
*/
7179
@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TransactionAutoConfiguration.class })
@@ -162,6 +170,28 @@ protected ConfigurableConversionService getConversionService() {
162170

163171
}
164172

173+
@Configuration(proxyBeanMethods = false)
174+
@ConditionalOnProperty(prefix = "spring.batch.job", name = "modular", havingValue = "true")
175+
static class SpringBootModularBatchConfiguration {
176+
177+
@Bean
178+
public JobLoader jobLoader(JobRegistry jobRegistry, ObjectProvider<StepRegistry> stepRegistry) {
179+
DefaultJobLoader jobLoader = new DefaultJobLoader(jobRegistry);
180+
stepRegistry.ifAvailable(jobLoader::setStepRegistry);
181+
return jobLoader;
182+
}
183+
184+
@Bean
185+
public AutomaticJobRegistrar automaticJobRegistrar(JobLoader jobLoader,
186+
ObjectProvider<ApplicationContextFactory> applicationContextFactories) {
187+
AutomaticJobRegistrar automaticJobRegistrar = new AutomaticJobRegistrar();
188+
automaticJobRegistrar.setJobLoader(jobLoader);
189+
applicationContextFactories.forEach(automaticJobRegistrar::addApplicationContextFactory);
190+
return automaticJobRegistrar;
191+
}
192+
193+
}
194+
165195
@Configuration(proxyBeanMethods = false)
166196
@Conditional(OnBatchDatasourceInitializationCondition.class)
167197
static class DataSourceInitializerConfiguration {

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,12 @@
501501
"description": "Execute all Spring Batch jobs in the context on startup.",
502502
"defaultValue": true
503503
},
504+
{
505+
"name": "spring.batch.job.modular",
506+
"type": "java.lang.Boolean",
507+
"description": "Whether the job configuration is going to be modularized like @EnableBatchProcessing(modular=true)",
508+
"defaultValue": false
509+
},
504510
{
505511
"name": "spring.batch.schema",
506512
"type": "java.lang.String",

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
import org.springframework.batch.core.configuration.JobFactory;
3838
import org.springframework.batch.core.configuration.JobRegistry;
3939
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
40+
import org.springframework.batch.core.configuration.support.ApplicationContextFactory;
4041
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
42+
import org.springframework.batch.core.configuration.support.GenericApplicationContextFactory;
4143
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
4244
import org.springframework.batch.core.explore.JobExplorer;
4345
import org.springframework.batch.core.job.AbstractJob;
@@ -93,6 +95,7 @@
9395
* @author Stephane Nicoll
9496
* @author Vedran Pavic
9597
* @author Kazuki Shimizu
98+
* @author Yanming Zhou
9699
*/
97100
@ExtendWith(OutputCaptureExtension.class)
98101
class BatchAutoConfigurationTests {
@@ -422,6 +425,19 @@ void conversionServiceCustomizersAreCalled() {
422425
});
423426
}
424427

428+
@Test
429+
void testModular() {
430+
this.contextRunner.withUserConfiguration(ModularConfiguration.class, EmbeddedDataSourceConfiguration.class)
431+
.withPropertyValues("spring.batch.job.modular=true")
432+
.run((context) -> {
433+
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
434+
assertThat(jobRegistry.getJobNames()).containsExactlyInAnyOrder("job", "discreteLocalJob");
435+
context.getBean(JobLauncher.class).run(jobRegistry.getJob("discreteLocalJob"), new JobParameters());
436+
assertThat(context.getBean(JobRepository.class)
437+
.getLastJobExecution("discreteLocalJob", new JobParameters())).isNotNull();
438+
});
439+
}
440+
425441
@Configuration(proxyBeanMethods = false)
426442
protected static class BatchDataSourceConfiguration {
427443

@@ -719,4 +735,19 @@ BatchConversionServiceCustomizer anotherBatchConversionServiceCustomizer() {
719735

720736
}
721737

738+
@Configuration(proxyBeanMethods = false)
739+
static class ModularConfiguration {
740+
741+
@Bean
742+
ApplicationContextFactory jobConfiguration() {
743+
return new GenericApplicationContextFactory(JobConfiguration.class);
744+
}
745+
746+
@Bean
747+
ApplicationContextFactory namedJobConfigurationWithLocalJob() {
748+
return new GenericApplicationContextFactory(NamedJobConfigurationWithLocalJob.class);
749+
}
750+
751+
}
752+
722753
}

spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto/batch.adoc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Spring Batch auto-configuration is enabled by adding `spring-boot-starter-batch`
2626
If a single `Job` is found in the application context, it is executed on startup (see {spring-boot-autoconfigure-module-code}/batch/JobLauncherApplicationRunner.java[`JobLauncherApplicationRunner`] for details).
2727
If multiple `Job` beans are found, the job that should be executed must be specified using configprop:spring.batch.job.name[].
2828

29-
To disable running a `Job` found in the application context, set the configprop:spring.batch.job.enabled[] to `false.`
29+
To disable running a `Job` found in the application context, set the configprop:spring.batch.job.enabled[] to `false`.
3030

3131
See {spring-boot-autoconfigure-module-code}/batch/BatchAutoConfiguration.java[BatchAutoConfiguration] for more details.
3232

@@ -60,3 +60,28 @@ This provides only one argument to the batch job: `someParameter=someValue`.
6060
Spring Batch requires a data store for the `Job` repository.
6161
If you use Spring Boot, you must use an actual database.
6262
Note that it can be an in-memory database, see {spring-batch-docs}job.html#configuringJobRepository[Configuring a Job Repository].
63+
64+
65+
66+
[[howto.batch.modularizing-job-configuration]]
67+
=== Modularizing Job Configuration
68+
To modularize job configuration into multiple application contexts, set the configprop:spring.batch.job.modular[] to `true`,
69+
and supply them in separate (child) contexts through {spring-batch-api}/core/configuration/support/ApplicationContextFactory.html[`ApplicationContextFactory`].
70+
71+
[source,java,indent=0,subs="verbatim"]
72+
----
73+
@Configuration(proxyBeanMethods = false)
74+
static class ModularBatchConfiguration {
75+
76+
@Bean
77+
ApplicationContextFactory job1Configuration() {
78+
return new GenericApplicationContextFactory(Job1Configuration.class);
79+
}
80+
81+
@Bean
82+
ApplicationContextFactory job2Configuration() {
83+
return new GenericApplicationContextFactory(Job2Configuration.class);
84+
}
85+
86+
}
87+
----

0 commit comments

Comments
 (0)