Add support for configuring a Batch-specific DataSource

See gh-17375
This commit is contained in:
Dmytro Nosan 2019-07-01 15:12:09 +03:00 committed by Andy Wilkinson
parent f7850ef898
commit f449665e2a
5 changed files with 91 additions and 9 deletions

View File

@ -76,8 +76,10 @@ public class BatchAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnBean(DataSource.class) @ConditionalOnBean(DataSource.class)
public BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource, ResourceLoader resourceLoader) { public BatchDataSourceInitializer batchDataSourceInitializer(ObjectProvider<DataSource> dataSource,
return new BatchDataSourceInitializer(dataSource, resourceLoader, this.properties); @BatchDataSource ObjectProvider<DataSource> batchDataSource, ResourceLoader resourceLoader) {
return new BatchDataSourceInitializer(batchDataSource.getIfAvailable(dataSource::getIfAvailable),
resourceLoader, this.properties);
} }
@Bean @Bean

View File

@ -36,6 +36,7 @@ import org.springframework.transaction.PlatformTransactionManager;
*/ */
@ConditionalOnClass(PlatformTransactionManager.class) @ConditionalOnClass(PlatformTransactionManager.class)
@ConditionalOnMissingBean(BatchConfigurer.class) @ConditionalOnMissingBean(BatchConfigurer.class)
@ConditionalOnBean(DataSource.class)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
class BatchConfigurerConfiguration { class BatchConfigurerConfiguration {
@ -44,9 +45,11 @@ class BatchConfigurerConfiguration {
static class JdbcBatchConfiguration { static class JdbcBatchConfiguration {
@Bean @Bean
BasicBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, BasicBatchConfigurer batchConfigurer(BatchProperties properties, ObjectProvider<DataSource> dataSource,
@BatchDataSource ObjectProvider<DataSource> batchDataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) { ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
return new BasicBatchConfigurer(properties, dataSource, transactionManagerCustomizers.getIfAvailable()); return new BasicBatchConfigurer(properties, batchDataSource.getIfAvailable(dataSource::getIfAvailable),
transactionManagerCustomizers.getIfAvailable());
} }
} }
@ -57,11 +60,12 @@ class BatchConfigurerConfiguration {
static class JpaBatchConfiguration { static class JpaBatchConfiguration {
@Bean @Bean
JpaBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, JpaBatchConfigurer batchConfigurer(BatchProperties properties, ObjectProvider<DataSource> dataSource,
@BatchDataSource ObjectProvider<DataSource> batchDataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
EntityManagerFactory entityManagerFactory) { EntityManagerFactory entityManagerFactory) {
return new JpaBatchConfigurer(properties, dataSource, transactionManagerCustomizers.getIfAvailable(), return new JpaBatchConfigurer(properties, batchDataSource.getIfAvailable(dataSource::getIfAvailable),
entityManagerFactory); transactionManagerCustomizers.getIfAvailable(), entityManagerFactory);
} }
} }

View File

@ -0,0 +1,39 @@
/*
* 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;
/**
* Qualifier annotation to allow a Batch-specific DataSource.
*
* @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 {
}

View File

@ -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.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.jdbc.DataSourceInitializationMode;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; 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) @Configuration(proxyBeanMethods = false)
static class EmptyConfiguration { static class EmptyConfiguration {

View File

@ -2429,8 +2429,12 @@ other factory that your application defines, if any.
This section answers questions that arise from using Spring Batch with Spring Boot. 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 NOTE: By default, batch applications require a `DataSource` to store job details.
want to deviate from that, you need to implement `BatchConfigurer`. See Batch autowires a single `DataSource` in your context and
uses that for processing. If you like to use a different `DataSource`, you can create
one and mark it is `@Bean` as `@BatchDataSource`. If you do so and want two data sources,
remember to create another one and mark it as `@Primary`. If you want to deviate from that,
you need to implement `BatchConfigurer`. See
{spring-batch-javadoc}/core/configuration/annotation/EnableBatchProcessing.html[The {spring-batch-javadoc}/core/configuration/annotation/EnableBatchProcessing.html[The
Javadoc of `@EnableBatchProcessing`] for more details. Javadoc of `@EnableBatchProcessing`] for more details.