有一个项目之前使用的SpringBoot的版本是1.5.6.RELEASE, 现在准备升级到2.1.0.RELEASE,突然发现数据库连接不上了,排查了一下发现是由于SpringBoot版本在2.0.0.RELEASE后的默认数据源不是tomcat的数据库连接池了;而项目正好没有指定数据库连接池,使用的是1.5.6.RELEASE默认的tomcat的连接池。
以下就以1.5.6.RELEASE和2.1.0.RELEASE为例:
* Copyright 2012-2016 the original author or authors.
package org.springframework.boot.autoconfigure.jdbc;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.util.ClassUtils;
/**
* Convenience class for building a {@link DataSource} with common implementations and
* properties. If Tomcat, HikariCP or Commons DBCP are on the classpath one of them will
* be selected (in that order with Tomcat first). In the interest of a uniform interface,
* and so that there can be a fallback to an embedded database if one can be detected on
* the classpath, only a small set of common configuration properties are supported. To
* inject additional properties into the result you can downcast it, or use
* {@code @ConfigurationProperties}.
*
* @author Dave Syer
* @since 1.1.0
*/
public class DataSourceBuilder {
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"org.apache.tomcat.jdbc.pool.DataSource",
"com.zaxxer.hikari.HikariDataSource",
"org.apache.commons.dbcp.BasicDataSource", // deprecated
"org.apache.commons.dbcp2.BasicDataSource" };
private Class<? extends DataSource> type;
private ClassLoader classLoader;
private Map<String, String> properties = new HashMap<String, String>();
public static DataSourceBuilder create() {
return new DataSourceBuilder(null);
}
public static DataSourceBuilder create(ClassLoader classLoader) {
return new DataSourceBuilder(classLoader);
}
public DataSourceBuilder(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public DataSource build() {
Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiate(type);
maybeGetDriverClassName();
bind(result);
return result;
}
private void maybeGetDriverClassName() {
if (!this.properties.containsKey("driverClassName")
&& this.properties.containsKey("url")) {
String url = this.properties.get("url");
String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
this.properties.put("driverClassName", driverClass);
}
}
private void bind(DataSource result) {
MutablePropertyValues properties = new MutablePropertyValues(this.properties);
new RelaxedDataBinder(result).withAlias("url", "jdbcUrl")
.withAlias("username", "user").bind(properties);
}
public DataSourceBuilder type(Class<? extends DataSource> type) {
this.type = type;
return this;
}
public DataSourceBuilder url(String url) {
this.properties.put("url", url);
return this;
}
public DataSourceBuilder driverClassName(String driverClassName) {
this.properties.put("driverClassName", driverClassName);
return this;
}
public DataSourceBuilder username(String username) {
this.properties.put("username", username);
return this;
}
public DataSourceBuilder password(String password) {
this.properties.put("password", password);
return this;
}
@SuppressWarnings("unchecked")
public Class<? extends DataSource> findType() {
if (this.type != null) {
return this.type;
}
for (String name : DATA_SOURCE_TYPE_NAMES) {
try {
return (Class<? extends DataSource>) ClassUtils.forName(name,
this.classLoader);
}
catch (Exception ex) {
// Swallow and continue
}
}
return null;
}
private Class<? extends DataSource> getType() {
Class<? extends DataSource> type = findType();
if (type != null) {
return type;
}
throw new IllegalStateException("No supported DataSource type found");
}
}
顺序按照DATA_SOURCE_TYPE_NAMES 数组中的顺序:
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"org.apache.tomcat.jdbc.pool.DataSource",
"com.zaxxer.hikari.HikariDataSource",
"org.apache.commons.dbcp.BasicDataSource", // deprecated
"org.apache.commons.dbcp2.BasicDataSource" };
* Copyright 2012-2018 the original author or authors.
package org.springframework.boot.jdbc;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.boot.context.properties.source.ConfigurationPropertyNameAliases;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.util.ClassUtils;
/**
* Convenience class for building a {@link DataSource} with common implementations and
* properties. If HikariCP, Tomcat or Commons DBCP are on the classpath one of them will
* be selected (in that order with Hikari first). In the interest of a uniform interface,
* and so that there can be a fallback to an embedded database if one can be detected on
* the classpath, only a small set of common configuration properties are supported. To
* inject additional properties into the result you can downcast it, or use
* {@code @ConfigurationProperties}.
*
* @param type of DataSource produced by the builder
* @author Dave Syer
* @author Madhura Bhave
* @since 2.0.0
*/
public final class DataSourceBuilder<T extends DataSource> {
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"com.zaxxer.hikari.HikariDataSource",
"org.apache.tomcat.jdbc.pool.DataSource",
"org.apache.commons.dbcp2.BasicDataSource" };
private Class<? extends DataSource> type;
private ClassLoader classLoader;
private Map<String, String> properties = new HashMap<>();
public static DataSourceBuilder<?> create() {
return new DataSourceBuilder<>(null);
}
public static DataSourceBuilder<?> create(ClassLoader classLoader) {
return new DataSourceBuilder<>(classLoader);
}
private DataSourceBuilder(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@SuppressWarnings("unchecked")
public T build() {
Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiateClass(type);
maybeGetDriverClassName();
bind(result);
return (T) result;
}
private void maybeGetDriverClassName() {
if (!this.properties.containsKey("driverClassName")
&& this.properties.containsKey("url")) {
String url = this.properties.get("url");
String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
this.properties.put("driverClassName", driverClass);
}
}
private void bind(DataSource result) {
ConfigurationPropertySource source = new MapConfigurationPropertySource(
this.properties);
ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();
aliases.addAliases("url", "jdbc-url");
aliases.addAliases("username", "user");
Binder binder = new Binder(source.withAliases(aliases));
binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(result));
}
@SuppressWarnings("unchecked")
public <D extends DataSource> DataSourceBuilder<D> type(Class<D> type) {
this.type = type;
return (DataSourceBuilder<D>) this;
}
public DataSourceBuilder<T> url(String url) {
this.properties.put("url", url);
return this;
}
public DataSourceBuilder<T> driverClassName(String driverClassName) {
this.properties.put("driverClassName", driverClassName);
return this;
}
public DataSourceBuilder<T> username(String username) {
this.properties.put("username", username);
return this;
}
public DataSourceBuilder<T> password(String password) {
this.properties.put("password", password);
return this;
}
@SuppressWarnings("unchecked")
public static Class<? extends DataSource> findType(ClassLoader classLoader) {
for (String name : DATA_SOURCE_TYPE_NAMES) {
try {
return (Class<? extends DataSource>) ClassUtils.forName(name,
classLoader);
}
catch (Exception ex) {
// Swallow and continue
}
}
return null;
}
private Class<? extends DataSource> getType() {
Class<? extends DataSource> type = (this.type != null) ? this.type
: findType(this.classLoader);
if (type != null) {
return type;
}
throw new IllegalStateException("No supported DataSource type found");
}
}
顺序也是按照DATA_SOURCE_TYPE_NAMES 数组中的顺序:
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"com.zaxxer.hikari.HikariDataSource",
"org.apache.tomcat.jdbc.pool.DataSource",
"org.apache.commons.dbcp2.BasicDataSource" };
使用时最好指定数据源格式,防止今后的升级中默认数据源的变动带来的不确定。