diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/AbstractBatchConfiguration.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/AbstractBatchConfiguration.java index 14ef6de1b..7c6918789 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/AbstractBatchConfiguration.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/AbstractBatchConfiguration.java @@ -25,7 +25,10 @@ import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -50,7 +53,7 @@ import org.springframework.util.Assert; public abstract class AbstractBatchConfiguration implements ImportAware, InitializingBean { @Autowired - private DataSource dataSource; + private ApplicationContext context; private BatchConfigurer configurer; @@ -153,7 +156,20 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial return this.configurer; } if (configurers == null || configurers.isEmpty()) { - DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(this.dataSource); + DataSource dataSource; + try { + dataSource = this.context.getBean(DataSource.class); + } catch (NoUniqueBeanDefinitionException exception) { + throw new IllegalStateException( + "Multiple data sources are defined in the application context and no primary candidate was found. " + + "To use the default BatchConfigurer, one of the data sources should be annotated with '@Primary'.", + exception); + } catch (NoSuchBeanDefinitionException exception) { + throw new IllegalStateException( + "To use the default BatchConfigurer, the application context must contain at least one data source.", + exception); + } + DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(dataSource); configurer.initialize(); this.configurer = configurer; return configurer; 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 33ab4284e..d89eaf5c7 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 @@ -62,7 +62,7 @@ import org.springframework.transaction.PlatformTransactionManager; * } * * - * The user should to provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in + * The user should provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in * the configuration class itself, e.g. * *
@@ -85,11 +85,8 @@ import org.springframework.transaction.PlatformTransactionManager; * } ** - * If multiple {@link javax.sql.DataSource}s are defined in the context, the one annotated with - * {@link org.springframework.context.annotation.Primary} will be used (Note that if none - * of them is annotated with {@link org.springframework.context.annotation.Primary}, the one - * named
dataSource will be used if any, otherwise a {@link UnsatisfiedDependencyException}
- * will be thrown).
+ * If multiple {@link javax.sql.DataSource}s are defined in the context, the primary autowire candidate
+ * will be used, otherwise an exception will be thrown.
*
* Note that only one of your configuration classes needs to have the @EnableBatchProcessing
* annotation. Once you have an @EnableBatchProcessing class in your configuration you will have an
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.java
index f6f9a36f8..caacabec7 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2021 the original author or authors.
+ * Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/InlineDataSourceDefinitionTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/InlineDataSourceDefinitionTests.java
new file mode 100644
index 000000000..d9a5d07b8
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/InlineDataSourceDefinitionTests.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.core.configuration.annotation;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class InlineDataSourceDefinitionTests {
+
+ @Test
+ public void testInlineDataSourceDefinition() throws Exception {
+ ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyJobConfiguration.class);
+ Job job = applicationContext.getBean(Job.class);
+ JobLauncher jobLauncher = applicationContext.getBean(JobLauncher.class);
+ JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class MyJobConfiguration {
+
+ private JobBuilderFactory jobs;
+ private StepBuilderFactory steps;
+
+ public MyJobConfiguration(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ this.jobs = jobs;
+ this.steps = steps;
+ }
+
+ @Bean
+ public Job job() {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> {
+ System.out.println("hello world");
+ return RepeatStatus.FINISHED;
+ })
+ .build())
+ .build();
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ return new EmbeddedDatabaseBuilder()
+ .setType(EmbeddedDatabaseType.H2)
+ .addScript("/org/springframework/batch/core/schema-drop-h2.sql")
+ .addScript("/org/springframework/batch/core/schema-h2.sql")
+ .generateUniqueName(true)
+ .build();
+ }
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithBatchConfigurerTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithBatchConfigurerTests.java
index a202bd531..445dae97d 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithBatchConfigurerTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithBatchConfigurerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,11 +21,14 @@ import javax.sql.DataSource;
import org.junit.Assert;
import org.junit.Test;
+import org.springframework.batch.core.Job;
import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.test.util.AopTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
@@ -35,11 +38,6 @@ import org.springframework.transaction.PlatformTransactionManager;
*/
public class TransactionManagerConfigurationWithBatchConfigurerTests extends TransactionManagerConfigurationTests {
- @Test(expected = UnsatisfiedDependencyException.class)
- public void testConfigurationWithNoDataSourceAndNoTransactionManager() {
- new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndNoTransactionManager.class);
- }
-
@Test
public void testConfigurationWithDataSourceAndNoTransactionManager() throws Exception {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BatchConfigurationWithDataSourceAndNoTransactionManager.class);
@@ -62,11 +60,7 @@ public class TransactionManagerConfigurationWithBatchConfigurerTests extends Tra
Assert.assertSame(getTransactionManagerSetOnJobRepository(applicationContext.getBean(JobRepository.class)), transactionManager);
}
- @EnableBatchProcessing
- public static class BatchConfigurationWithNoDataSourceAndNoTransactionManager {
-
- }
-
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithDataSourceAndNoTransactionManager {
@Bean
@@ -80,6 +74,7 @@ public class TransactionManagerConfigurationWithBatchConfigurerTests extends Tra
}
}
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithDataSourceAndTransactionManager {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithoutBatchConfigurerTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithoutBatchConfigurerTests.java
index 23fc07587..c384a2e5e 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithoutBatchConfigurerTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/annotation/TransactionManagerConfigurationWithoutBatchConfigurerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,11 +21,15 @@ import javax.sql.DataSource;
import org.junit.Assert;
import org.junit.Test;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.test.util.AopTestUtils;
@@ -36,14 +40,22 @@ import org.springframework.transaction.PlatformTransactionManager;
*/
public class TransactionManagerConfigurationWithoutBatchConfigurerTests extends TransactionManagerConfigurationTests {
- @Test(expected = UnsatisfiedDependencyException.class)
+ @Test(expected = IllegalStateException.class)
public void testConfigurationWithNoDataSourceAndNoTransactionManager() {
- new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndNoTransactionManager.class);
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndNoTransactionManager.class);
+ // beans created by `@EnableBatchProcessing` are lazy proxies, SimpleBatchConfiguration.initialize is only triggered
+ // when a method is called on one of these proxies
+ JobRepository jobRepository = context.getBean(JobRepository.class);
+ Assert.assertFalse(jobRepository.isJobInstanceExists("myJob", new JobParameters()));
}
- @Test(expected = UnsatisfiedDependencyException.class)
+ @Test(expected = IllegalStateException.class)
public void testConfigurationWithNoDataSourceAndTransactionManager() {
- new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndTransactionManager.class);
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BatchConfigurationWithNoDataSourceAndTransactionManager.class);
+ // beans created by `@EnableBatchProcessing` are lazy proxies, SimpleBatchConfiguration.initialize is only triggered
+ // when a method is called on one of these proxies
+ JobRepository jobRepository = context.getBean(JobRepository.class);
+ Assert.assertFalse(jobRepository.isJobInstanceExists("myJob", new JobParameters()));
}
@Test
@@ -73,14 +85,15 @@ public class TransactionManagerConfigurationWithoutBatchConfigurerTests extends
// In this case, the supplied primary transaction manager won't be used by batch and a DataSourceTransactionManager will be used instead.
// The user has to provide a custom BatchConfigurer.
Assert.assertTrue(getTransactionManagerSetOnJobRepository(applicationContext.getBean(JobRepository.class)) instanceof DataSourceTransactionManager);
-
}
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithNoDataSourceAndNoTransactionManager {
}
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithNoDataSourceAndTransactionManager {
@@ -90,6 +103,7 @@ public class TransactionManagerConfigurationWithoutBatchConfigurerTests extends
}
}
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithDataSourceAndNoTransactionManager {
@@ -99,6 +113,7 @@ public class TransactionManagerConfigurationWithoutBatchConfigurerTests extends
}
}
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithDataSourceAndOneTransactionManager {
@@ -113,6 +128,7 @@ public class TransactionManagerConfigurationWithoutBatchConfigurerTests extends
}
}
+ @Configuration
@EnableBatchProcessing
public static class BatchConfigurationWithDataSourceAndMultipleTransactionManagers {