Skip to content

Commit

Permalink
Use deterministic DataSource config import order
Browse files Browse the repository at this point in the history
Update DataSourceAutoConfiguration so that pooled datasource
configurations are only loaded via an @import. If left as nested
classes, the load order is JVM specific and can result in the wrong
configuration being loaded.

Closes gh-2183
  • Loading branch information
philwebb committed Feb 5, 2016
1 parent 3d03554 commit ed01ae9
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import javax.sql.DataSource;
import javax.sql.XADataSource;

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.DataSourceProxy;
Expand All @@ -39,7 +38,6 @@
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerPostProcessor.Registrar;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
Expand Down Expand Up @@ -72,6 +70,12 @@ public class DataSourceAutoConfiguration {
private static final Log logger = LogFactory
.getLog(DataSourceAutoConfiguration.class);

@Bean
@ConditionalOnMissingBean
public DataSourceInitializer dataSourceInitializer() {
return new DataSourceInitializer();
}

/**
* Determines if the {@code dataSource} being used by Spring was created from
* {@link EmbeddedDataSourceConfiguration}.
Expand All @@ -94,93 +98,15 @@ public static boolean containsAutoConfiguredDataSource(
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {

}

@Configuration
@ConditionalOnMissingBean(DataSourceInitializer.class)
protected static class DataSourceInitializerConfiguration {

@Bean
public DataSourceInitializer dataSourceInitializer() {
return new DataSourceInitializer();
}

}

@Configuration
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,
DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class })
protected static class PooledDataSourceConfiguration {

@SuppressWarnings("unchecked")
private static <T> T createDataSource(DataSourceProperties properties,
Class<? extends DataSource> type) {
return (T) DataSourceBuilder.create(properties.getClassLoader()).type(type)
.driverClassName(properties.determineDriverClassName())
.url(properties.determineUrl())
.username(properties.determineUsername())
.password(properties.determinePassword()).build();
}

@Configuration
@Import({ TomcatDataSourceConfiguration.class,
HikariDataSourceConfiguration.class, DbcpDataSourceConfiguration.class,
Dbcp2DataSourceConfiguration.class })
protected static class AllDataSourceConfiguration {
}

@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
protected static class TomcatDataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.tomcat")
public org.apache.tomcat.jdbc.pool.DataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.tomcat.jdbc.pool.DataSource.class);
}

}

@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
protected static class HikariDataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
return createDataSource(properties, HikariDataSource.class);
}
}

@ConditionalOnClass(org.apache.commons.dbcp.BasicDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp.BasicDataSource", matchIfMissing = true)
protected static class DbcpDataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.dbcp")
public org.apache.commons.dbcp.BasicDataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.commons.dbcp.BasicDataSource.class);
}
}

@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)
protected static class Dbcp2DataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.dbcp2")
public org.apache.commons.dbcp2.BasicDataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.commons.dbcp2.BasicDataSource.class);
}
}

}

@Configuration
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2012-2015 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
*
* http://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.jdbc;

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;

/**
* Actual DataSource configurations imported by {@link DataSourceAutoConfiguration}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
*/
abstract class DataSourceConfiguration {

@SuppressWarnings("unchecked")
protected <T> T createDataSource(DataSourceProperties properties,
Class<? extends DataSource> type) {
return (T) DataSourceBuilder.create(properties.getClassLoader()).type(type)
.driverClassName(properties.determineDriverClassName())
.url(properties.determineUrl()).username(properties.determineUsername())
.password(properties.determinePassword()).build();
}

@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
static class Tomcat extends DataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.tomcat")
public org.apache.tomcat.jdbc.pool.DataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.tomcat.jdbc.pool.DataSource.class);
}

}

@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
static class Hikari extends DataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
return createDataSource(properties, HikariDataSource.class);
}
}

@ConditionalOnClass(org.apache.commons.dbcp.BasicDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp.BasicDataSource", matchIfMissing = true)
static class Dbcp extends DataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.dbcp")
public org.apache.commons.dbcp.BasicDataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.commons.dbcp.BasicDataSource.class);
}
}

@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)
static class Dbcp2 extends DataSourceConfiguration {

@Bean
@ConfigurationProperties("spring.datasource.dbcp2")
public org.apache.commons.dbcp2.BasicDataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.commons.dbcp2.BasicDataSource.class);
}
}

}

0 comments on commit ed01ae9

Please sign in to comment.