Skip to content

Commit b4cb4d6

Browse files
committed
Remove datasource autowiring in AbstractBatchConfiguration
Before this commit, the datasource was autowired in AbstractBatchConfiguration. This was causing context startup failures when no datasource or more than one datasource is present in the context. This commit fixes these failures by looking for the datasource in the application context. This also prevents cyclic configuration dependencies when the datasource bean is defined in the same class where other batch artifacts are autowired. Issue spring-projects#3991
1 parent a19eefa commit b4cb4d6

File tree

5 files changed

+107
-31
lines changed

5 files changed

+107
-31
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
import org.springframework.batch.core.launch.JobLauncher;
2626
import org.springframework.batch.core.repository.JobRepository;
2727
import org.springframework.beans.factory.InitializingBean;
28+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
29+
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
2830
import org.springframework.beans.factory.annotation.Autowired;
31+
import org.springframework.context.ApplicationContext;
2932
import org.springframework.context.annotation.Bean;
3033
import org.springframework.context.annotation.Configuration;
3134
import org.springframework.context.annotation.Import;
@@ -50,7 +53,7 @@
5053
public abstract class AbstractBatchConfiguration implements ImportAware, InitializingBean {
5154

5255
@Autowired
53-
private DataSource dataSource;
56+
private ApplicationContext context;
5457

5558
private BatchConfigurer configurer;
5659

@@ -153,7 +156,15 @@ protected BatchConfigurer getConfigurer(Collection<BatchConfigurer> configurers)
153156
return this.configurer;
154157
}
155158
if (configurers == null || configurers.isEmpty()) {
156-
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(this.dataSource);
159+
DataSource dataSource;
160+
try {
161+
dataSource = this.context.getBean(DataSource.class);
162+
} catch (NoSuchBeanDefinitionException exception) {
163+
throw new IllegalStateException(
164+
"To use the default BatchConfigurer the context must contain precisely one DataSource",
165+
exception);
166+
}
167+
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(dataSource);
157168
configurer.initialize();
158169
this.configurer = configurer;
159170
return configurer;

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
* }
6363
* </pre>
6464
*
65-
* The user should to provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in
65+
* The user should provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in
6666
* the configuration class itself, e.g.
6767
*
6868
* <pre class="code">
@@ -85,11 +85,8 @@
8585
* }
8686
* </pre>
8787
*
88-
* If multiple {@link javax.sql.DataSource}s are defined in the context, the one annotated with
89-
* {@link org.springframework.context.annotation.Primary} will be used (Note that if none
90-
* of them is annotated with {@link org.springframework.context.annotation.Primary}, the one
91-
* named <code>dataSource</code> will be used if any, otherwise a {@link UnsatisfiedDependencyException}
92-
* will be thrown).
88+
* If multiple {@link javax.sql.DataSource}s are defined in the context, the primary autowire candidate
89+
* will be used, otherwise an exception will be thrown.
9390
*
9491
* Note that only one of your configuration classes needs to have the <code>&#064;EnableBatchProcessing</code>
9592
* annotation. Once you have an <code>&#064;EnableBatchProcessing</code> class in your configuration you will have an
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.batch.core.configuration.annotation;
17+
18+
import javax.sql.DataSource;
19+
20+
import org.junit.Assert;
21+
import org.junit.Test;
22+
23+
import org.springframework.batch.core.ExitStatus;
24+
import org.springframework.batch.core.Job;
25+
import org.springframework.batch.core.JobExecution;
26+
import org.springframework.batch.core.JobParameters;
27+
import org.springframework.batch.core.JobParametersInvalidException;
28+
import org.springframework.batch.core.launch.JobLauncher;
29+
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
30+
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
31+
import org.springframework.batch.core.repository.JobRestartException;
32+
import org.springframework.batch.repeat.RepeatStatus;
33+
import org.springframework.beans.factory.annotation.Autowired;
34+
import org.springframework.context.ApplicationContext;
35+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
36+
import org.springframework.context.annotation.Bean;
37+
import org.springframework.context.annotation.Configuration;
38+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
39+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
40+
41+
// https://github.com/spring-projects/spring-batch/issues/3991
42+
public class InlineDataSourceDefinitionTests {
43+
44+
@Test
45+
public void testInlineDataSourceDefinition() throws Exception {
46+
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyJobConfiguration.class);
47+
Job job = applicationContext.getBean(Job.class);
48+
JobLauncher jobLauncher = applicationContext.getBean(JobLauncher.class);
49+
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
50+
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
51+
}
52+
53+
@Configuration
54+
@EnableBatchProcessing
55+
static class MyJobConfiguration {
56+
57+
private JobBuilderFactory jobs;
58+
private StepBuilderFactory steps;
59+
60+
public MyJobConfiguration(JobBuilderFactory jobs, StepBuilderFactory steps) {
61+
this.jobs = jobs;
62+
this.steps = steps;
63+
}
64+
65+
@Bean
66+
public Job job() {
67+
return jobs.get("job")
68+
.start(steps.get("step")
69+
.tasklet((contribution, chunkContext) -> {
70+
System.out.println("hello world");
71+
return RepeatStatus.FINISHED;
72+
})
73+
.build())
74+
.build();
75+
}
76+
77+
@Bean
78+
public DataSource dataSource() {
79+
return new EmbeddedDatabaseBuilder()
80+
.setType(EmbeddedDatabaseType.H2)
81+
.addScript("/org/springframework/batch/core/schema-drop-h2.sql")
82+
.addScript("/org/springframework/batch/core/schema-h2.sql")
83+
.generateUniqueName(true)
84+
.build();
85+
}
86+
}
87+
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2021 the original author or authors.
2+
* Copyright 2018-2022 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.
@@ -21,7 +21,9 @@
2121
import org.junit.Assert;
2222
import org.junit.Test;
2323

24+
import org.springframework.batch.core.Job;
2425
import org.springframework.batch.core.repository.JobRepository;
26+
import org.springframework.batch.repeat.RepeatStatus;
2527
import org.springframework.beans.factory.UnsatisfiedDependencyException;
2628
import org.springframework.context.ApplicationContext;
2729
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -35,11 +37,6 @@
3537
*/
3638
public class TransactionManagerConfigurationWithBatchConfigurerTests extends TransactionManagerConfigurationTests {
3739

38-
@Test(expected = UnsatisfiedDependencyException.class)
39-
public void testConfigurationWithNoDataSourceAndNoTransactionManager() {
40-
new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndNoTransactionManager.class);
41-
}
42-
4340
@Test
4441
public void testConfigurationWithDataSourceAndNoTransactionManager() throws Exception {
4542
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BatchConfigurationWithDataSourceAndNoTransactionManager.class);

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

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2021 the original author or authors.
2+
* Copyright 2018-2022 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.
@@ -36,16 +36,6 @@
3636
*/
3737
public class TransactionManagerConfigurationWithoutBatchConfigurerTests extends TransactionManagerConfigurationTests {
3838

39-
@Test(expected = UnsatisfiedDependencyException.class)
40-
public void testConfigurationWithNoDataSourceAndNoTransactionManager() {
41-
new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndNoTransactionManager.class);
42-
}
43-
44-
@Test(expected = UnsatisfiedDependencyException.class)
45-
public void testConfigurationWithNoDataSourceAndTransactionManager() {
46-
new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndTransactionManager.class);
47-
}
48-
4939
@Test
5040
public void testConfigurationWithDataSourceAndNoTransactionManager() throws Exception {
5141
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BatchConfigurationWithDataSourceAndNoTransactionManager.class);
@@ -73,12 +63,6 @@ public void testConfigurationWithDataSourceAndMultipleTransactionManagers() thro
7363
// In this case, the supplied primary transaction manager won't be used by batch and a DataSourceTransactionManager will be used instead.
7464
// The user has to provide a custom BatchConfigurer.
7565
Assert.assertTrue(getTransactionManagerSetOnJobRepository(applicationContext.getBean(JobRepository.class)) instanceof DataSourceTransactionManager);
76-
77-
}
78-
79-
@EnableBatchProcessing
80-
public static class BatchConfigurationWithNoDataSourceAndNoTransactionManager {
81-
8266
}
8367

8468
@EnableBatchProcessing

0 commit comments

Comments
 (0)