diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java index 996715629c0..7411f3ce197 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java @@ -76,8 +76,10 @@ public class BatchAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnBean(DataSource.class) - public BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource, ResourceLoader resourceLoader) { - return new BatchDataSourceInitializer(dataSource, resourceLoader, this.properties); + public BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource, + @BatchDataSource ObjectProvider batchDataSource, ResourceLoader resourceLoader) { + return new BatchDataSourceInitializer(batchDataSource.getIfAvailable(() -> dataSource), resourceLoader, + this.properties); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchConfigurerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchConfigurerConfiguration.java index 36264a8bf24..415f479a391 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchConfigurerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchConfigurerConfiguration.java @@ -45,8 +45,10 @@ class BatchConfigurerConfiguration { @Bean BasicBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, + @BatchDataSource ObjectProvider batchDataSource, ObjectProvider transactionManagerCustomizers) { - return new BasicBatchConfigurer(properties, dataSource, transactionManagerCustomizers.getIfAvailable()); + return new BasicBatchConfigurer(properties, batchDataSource.getIfAvailable(() -> dataSource), + transactionManagerCustomizers.getIfAvailable()); } } @@ -58,10 +60,11 @@ class BatchConfigurerConfiguration { @Bean JpaBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, + @BatchDataSource ObjectProvider batchDataSource, ObjectProvider transactionManagerCustomizers, EntityManagerFactory entityManagerFactory) { - return new JpaBatchConfigurer(properties, dataSource, transactionManagerCustomizers.getIfAvailable(), - entityManagerFactory); + return new JpaBatchConfigurer(properties, batchDataSource.getIfAvailable(() -> dataSource), + transactionManagerCustomizers.getIfAvailable(), entityManagerFactory); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSource.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSource.java new file mode 100644 index 00000000000..fe12c8fd2d7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSource.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2019 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.boot.autoconfigure.batch; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Primary; + +/** + * Qualifier annotation for a DataSource to be injected into Batch auto-configuration. Can + * be used on a secondary data source, if there is another one marked as + * {@link Primary @Primary}. + * + * @author Dmytro Nosan + * @since 2.2.0 + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Qualifier +public @interface BatchDataSource { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java index d9ed265e860..aac755cdf4f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java @@ -49,10 +49,12 @@ import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfigurati import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; @@ -233,6 +235,37 @@ class BatchAutoConfigurationTests { }); } + @Test + void testBatchDataSource() { + this.contextRunner.withUserConfiguration(TestConfiguration.class, BatchDataSourceConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(BatchConfigurer.class) + .hasSingleBean(BatchDataSourceInitializer.class).hasBean("batchDataSource"); + DataSource batchDataSource = context.getBean("batchDataSource", DataSource.class); + assertThat(context.getBean(BatchConfigurer.class)).hasFieldOrPropertyWithValue("dataSource", + batchDataSource); + assertThat(context.getBean(BatchDataSourceInitializer.class)) + .hasFieldOrPropertyWithValue("dataSource", batchDataSource); + }); + } + + @Configuration(proxyBeanMethods = false) + protected static class BatchDataSourceConfiguration { + + @Bean + @Primary + public DataSource normalDataSource() { + return DataSourceBuilder.create().url("jdbc:hsqldb:mem:normal").username("sa").build(); + } + + @BatchDataSource + @Bean + public DataSource batchDataSource() { + return DataSourceBuilder.create().url("jdbc:hsqldb:mem:batchdatasource").username("sa").build(); + } + + } + @Configuration(proxyBeanMethods = false) static class EmptyConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index d8dc41015d0..2a39ef62f7d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -2429,9 +2429,13 @@ other factory that your application defines, if any. This section answers questions that arise from using Spring Batch with Spring Boot. -NOTE: By default, batch applications require a `DataSource` to store job details. If you -want to deviate from that, you need to implement `BatchConfigurer`. See -{spring-batch-javadoc}/core/configuration/annotation/EnableBatchProcessing.html[The +NOTE: By default, batch applications require a `DataSource` to store job details. +Batch autowires a single `DataSource` in your context and uses that for processing. To +have Batch use a `DataSource` other than the application’s main `DataSource`, declare a +`DataSource` bean, annotating its `@Bean` method with `@BatchDataSource`. If you do so and +want two data sources, remember to create another one and mark it as `@Primary`. To take +greater control, implement `BatchConfigurer`. See +{spring-batch-javadoc}/core/configuration/annotation/EnableBatchProcessing.html[the Javadoc of `@EnableBatchProcessing`] for more details. For more about Spring Batch, see the https://projects.spring.io/spring-batch/[Spring Batch