springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich。
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。springboot系列代码全部上传至GitHub:https://github.com/liubenlong/springboot2_demo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;
之前讲了springboot中如何配置MySQL以及配置多数据源,参数也都配置好了,那么springboot中到底如何选择的呢?
声明:笔者使用的springboot版本是1.5.3.RELEASE
springboot自动装配的过程就不说了,直接上核心代码。
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
该类是springboot加载数据源的核心配置类。
我们去看连接池的选择:
@Configuration
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,
DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class,
DataSourceConfiguration.Generic.class })
@SuppressWarnings("deprecation")
protected static class PooledDataSourceConfiguration {
}
PooledDataSourceConfiguration
上面的注解包含了tomcat连接池,dbcp,dbcp2等主流连接池。到底选择哪个连接池呢?(选择不同的连接池,application.properties配置不同)
一步一步往下跟:
进入PooledDataSourceCondition
进入PooledDataSourceAvailableCondition
static class PooledDataSourceAvailableCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("PooledDataSource");
if (getDataSourceClassLoader(context) != null) {
return ConditionOutcome
.match(message.foundExactly("supported DataSource"));
}
return ConditionOutcome
.noMatch(message.didNotFind("supported DataSource").atAll());
}
/**
* Returns the class loader for the {@link DataSource} class. Used to ensure that
* the driver class can actually be loaded by the data source.
* @param context the condition context
* @return the class loader
*/
private ClassLoader getDataSourceClassLoader(ConditionContext context) {
Class> dataSourceClass = new DataSourceBuilder(context.getClassLoader())
.findType();/*找到源头了*/
return (dataSourceClass == null ? null : dataSourceClass.getClassLoader());
}
}
进入findtype方法:
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 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" };
在findType()
方法中遍历该数组,从前往后,加载到哪个类就使用哪个类的连接池。
可能会因为不同项目中类不同,导致使用不同的连接池,所以最好就是在这里加个断点,亲自看一下最终选定的是哪个连接池
上图可见,笔者使用的是Tomcat连接池:org.apache.tomcat.jdbc.pool.DataSource
进入org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer
类,里面有init方法,是启动的时候加载的。属性文件以及datasource的配置就是在这里完成的。
@PostConstruct
public void init() {
if (!this.properties.isInitialize()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
false).length > 0) {
//加载dataSource 类,确认使用哪个连接池,
this.dataSource = this.applicationContext.getBean(DataSource.class);
}
if (this.dataSource == null) {//在这里查看DataSource的配置信息
logger.debug("No DataSource found so not initializing");
return;
}
runSchemaScripts();
}
在这里加个断点 ,查看最终使用的哪个连接池,以及我们的配置是否生效。
好了,接下来就是去看源码org.apache.tomcat.jdbc.pool.DataSource
或者官方文档,去配置参数了.
配置信息可以参考这两个类:
public class DataSourceProxy implements PoolConfiguration {
private static final Log log = LogFactory.getLog(DataSourceProxy.class);
//链接配置
protected volatile ConnectionPool pool = null;
//连接池配置
protected volatile PoolConfiguration poolProperties = null;
//省略代码......
}
springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich。
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。springboot系列代码全部上传至GitHub:https://github.com/liubenlong/springboot2_demo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;
测试DB连接,最大等待时间,DB测试
使用druid连接池带来的坑testOnBorrow=false