From ad859028809417396ca30cfe9842c701da789e0a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 1 Jun 2017 10:08:13 +0200 Subject: [PATCH] Reuse JdbcTemplate in NamedParameterJdbcTemplate This commit makes sure to reuse an existing or auto-configured `JdbcTemplate` when auto-configuring a `NamedParameterJdbcTemplate`. This ensures that whatever customizations have been applied on the `JdbcTemplate` are properly shared. Closes gh-4945 --- .../jdbc/JdbcTemplateAutoConfiguration.java | 41 ++++++++----- .../JdbcTemplateAutoConfigurationTests.java | 57 ++++++++++++++++++- .../main/asciidoc/spring-boot-features.adoc | 3 + 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfiguration.java index 1d60a9cf1f..beed059122 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; @@ -47,24 +48,36 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class JdbcTemplateAutoConfiguration { - private final DataSource dataSource; + @Configuration + static class JdbcTemplateConfiguration { + + private final DataSource dataSource; + + JdbcTemplateConfiguration(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Bean + @Primary + @ConditionalOnMissingBean(JdbcOperations.class) + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(this.dataSource); + } - public JdbcTemplateAutoConfiguration(DataSource dataSource) { - this.dataSource = dataSource; } - @Bean - @Primary - @ConditionalOnMissingBean(JdbcOperations.class) - public JdbcTemplate jdbcTemplate() { - return new JdbcTemplate(this.dataSource); - } + @Configuration + @Import(JdbcTemplateConfiguration.class) + static class NamedParameterJdbcTemplateConfiguration { + + @Bean + @Primary + @ConditionalOnSingleCandidate(JdbcTemplate.class) + @ConditionalOnMissingBean(NamedParameterJdbcOperations.class) + public NamedParameterJdbcTemplate namedParameterJdbcTemplate(JdbcTemplate jdbcTemplate) { + return new NamedParameterJdbcTemplate(jdbcTemplate); + } - @Bean - @Primary - @ConditionalOnMissingBean(NamedParameterJdbcOperations.class) - public NamedParameterJdbcTemplate namedParameterJdbcTemplate() { - return new NamedParameterJdbcTemplate(this.dataSource); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java index 6a8967e977..f492e75dce 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java @@ -28,12 +28,14 @@ import org.springframework.context.ConfigurableApplicationContext; 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.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link JdbcTemplateAutoConfiguration}. @@ -56,7 +58,7 @@ public class JdbcTemplateAutoConfigurationTests { @Test public void testJdbcTemplateExists() { load(); - assertThat(this.context.getBeansOfType(JdbcTemplate.class)).hasSize(1); + assertThat(this.context.getBeansOfType(JdbcOperations.class)).hasSize(1); JdbcTemplate jdbcTemplate = this.context.getBean(JdbcTemplate.class); assertThat(jdbcTemplate.getDataSource()).isEqualTo( this.context.getBean(DataSource.class)); @@ -65,7 +67,7 @@ public class JdbcTemplateAutoConfigurationTests { @Test public void testJdbcTemplateExistsWithCustomDataSource() { load(TestDataSourceConfiguration.class); - assertThat(this.context.getBeansOfType(JdbcTemplate.class)).hasSize(1); + assertThat(this.context.getBeansOfType(JdbcOperations.class)).hasSize(1); JdbcTemplate jdbcTemplate = this.context.getBean(JdbcTemplate.class); assertThat(jdbcTemplate).isNotNull(); assertThat(jdbcTemplate.getDataSource()).isEqualTo( @@ -77,6 +79,10 @@ public class JdbcTemplateAutoConfigurationTests { load(); assertThat(this.context.getBeansOfType(NamedParameterJdbcOperations.class)) .hasSize(1); + NamedParameterJdbcTemplate namedParameterJdbcTemplate = this.context.getBean( + NamedParameterJdbcTemplate.class); + assertThat(namedParameterJdbcTemplate.getJdbcOperations()).isEqualTo( + this.context.getBean(JdbcOperations.class)); } @Test @@ -87,6 +93,13 @@ public class JdbcTemplateAutoConfigurationTests { .isEmpty(); } + @Test + public void testMultiJdbcTemplate() { + load(MultiJdbcTemplateConfiguration.class); + assertThat(this.context.getBeansOfType(NamedParameterJdbcOperations.class)) + .isEmpty(); + } + @Test public void testMultiDataSourceUsingPrimary() { load(MultiDataSourceUsingPrimaryConfiguration.class); @@ -97,6 +110,15 @@ public class JdbcTemplateAutoConfigurationTests { .isEqualTo(this.context.getBean("test1DataSource")); } + @Test + public void testMultiJdbcTemplateUsingPrimary() { + load(MultiJdbcTemplateUsingPrimaryConfiguration.class); + assertThat(this.context.getBeansOfType(NamedParameterJdbcOperations.class)) + .hasSize(1); + assertThat(this.context.getBean(NamedParameterJdbcTemplate.class) + .getJdbcOperations()).isEqualTo(this.context.getBean("test1Template")); + } + @Test public void testExistingCustomJdbcTemplate() { load(CustomConfiguration.class); @@ -159,4 +181,35 @@ public class JdbcTemplateAutoConfigurationTests { } + @Configuration + static class MultiJdbcTemplateConfiguration { + + @Bean + public JdbcTemplate test1Template() { + return mock(JdbcTemplate.class); + } + + @Bean + public JdbcTemplate test2Template() { + return mock(JdbcTemplate.class); + } + + } + + @Configuration + static class MultiJdbcTemplateUsingPrimaryConfiguration { + + @Bean + @Primary + public JdbcTemplate test1Template() { + return mock(JdbcTemplate.class); + } + + @Bean + public JdbcTemplate test2Template() { + return mock(JdbcTemplate.class); + } + + } + } diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1e67163738..c15cc9b915 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -2932,6 +2932,9 @@ you can `@Autowire` them directly into your own beans: } ---- +TIP: The `NamedParameterJdbcTemplate` reuses the same `JdbcTemplate` instance behind the +scene. If more than one `JdbcTemplate` is defined and no primary candidate exists, the +`NamedParameterJdbcTemplate` is not auto-configured. [[boot-features-jpa-and-spring-data]]