数据库连接池 -Druid 源码学习(一)
作者:wjchenge
- 2022 年 5 月 11 日
本文字数:2838 字
阅读完需:约 9 分钟
1、简介
在本文中,我们将了解 com.alibaba.druid.pool.DruidDataSource#init 方法的执行流程。
2、初始化流程
1、利用双重检查锁(Double-Check Locking)保证只初始化一次
if (inited) {
return;
}
// bug fixed for dead lock, for issue #2980
// 利用类加载机制(天然线程安全,保证类只加载一次)实现驱动只注册一次
DruidDriver.getInstance();
final ReentrantLock lock = this.lock;
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
throw new SQLException("interrupt", e);
}
boolean init = false;
try {
if (inited) {
return;
}
复制代码
2、获取当前代码执行的堆栈信息
initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());
复制代码
3、解析包装代理的数据库连接,添加用户配置的过滤器
if (this.jdbcUrl != null) {
this.jdbcUrl = this.jdbcUrl.trim();
initFromWrapDriverUrl();
}
复制代码
4、执行过滤器的初始化方法
for (Filter filter : filters) {
filter.init(this);
}
复制代码
5、参数校验和赋值
if (this.dbTypeName == null || this.dbTypeName.length() == 0) {
this.dbTypeName = JdbcUtils.getDbType(jdbcUrl, null);
}
DbType dbType = DbType.of(this.dbTypeName);
if (dbType == DbType.mysql
|| dbType == DbType.mariadb
|| dbType == DbType.oceanbase
|| dbType == DbType.ads) {
boolean cacheServerConfigurationSet = false;
if (this.connectProperties.containsKey("cacheServerConfiguration")) {
cacheServerConfigurationSet = true;
} else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {
cacheServerConfigurationSet = true;
}
if (cacheServerConfigurationSet) {
this.connectProperties.put("cacheServerConfiguration", "true");
}
}
if (maxActive <= 0) {
throw new IllegalArgumentException("illegal maxActive " + maxActive);
}
if (maxActive < minIdle) {
throw new IllegalArgumentException("illegal maxActive " + maxActive);
}
if (getInitialSize() > maxActive) {
throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActive " + maxActive);
}
if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) {
throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true");
}
if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
}
if (keepAlive && keepAliveBetweenTimeMillis <= timeBetweenEvictionRunsMillis) {
throw new SQLException("keepAliveBetweenTimeMillis must be grater than timeBetweenEvictionRunsMillis");
}
if (this.driverClass != null) {
this.driverClass = driverClass.trim();
}
复制代码
6、初始化部分参数
// 通过spi机制加载用户自定义的过滤器
initFromSPIServiceLoader();
// 解析兼容部分特殊驱动
resolveDriver();
// oracle、db2、mysql特殊检查处理
initCheck();
// 初始化ExceptionSorter,
initExceptionSorter();
// 初始化ValidConnectionChecker
initValidConnectionChecker();
// 检查validationQuery参数配置是否完整
validationQueryCheck();
复制代码
7、是否使用全局数据源统计
if (isUseGlobalDataSourceStat()) {
dataSourceStat = JdbcDataSourceStat.getGlobal();
if (dataSourceStat == null) {
dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbTypeName);
JdbcDataSourceStat.setGlobal(dataSourceStat);
}
if (dataSourceStat.getDbType() == null) {
dataSourceStat.setDbType(this.dbTypeName);
}
} else {
dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbTypeName, this.connectProperties);
}
dataSourceStat.setResetStatEnable(this.resetStatEnable);
复制代码
8、初始化连接池
// 保存正常的连接,获取的数据库连接就是从这个数组获取
connections = new DruidConnectionHolder[maxActive];
// 保存需要丢弃的连接
evictConnections = new DruidConnectionHolder[maxActive];
// 保存需要进行keepAlive检查的连接
keepAliveConnections = new DruidConnectionHolder[maxActive];
复制代码
9、连接池初始化连接
// 异步初始化连接
if (createScheduler != null && asyncInit) {
for (int i = 0; i < initialSize; ++i) {
submitCreateTask(true);
}
} else if (!asyncInit) {
// init connections
// 同步初始化连接
while (poolingCount < initialSize) {
try {
PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
connections[poolingCount++] = holder;
} catch (SQLException ex) {
LOG.error("init datasource error, url: " + this.getUrl(), ex);
if (initExceptionThrow) {
connectError = ex;
break;
} else {
Thread.sleep(3000);
}
}
}
复制代码
10、开启三个守护线程
// 打印线程池配置信息
createAndLogThread();
// 线程池扩容
createAndStartCreatorThread();
// 线程池缩容
createAndStartDestroyThread();
复制代码
11、确保最小空闲连接
if (keepAlive) {
// async fill to minIdle
if (createScheduler != null) {
for (int i = 0; i < minIdle; ++i) {
submitCreateTask(true);
}
} else {
this.emptySignal();
}
}
复制代码
12、最后设置初始状态为完成,并释放锁,打印初始化情况日志
inited = true;
lock.unlock();
if (init && LOG.isInfoEnabled()) {
String msg = "{dataSource-" + this.getID();
if (this.name != null && !this.name.isEmpty()) {
msg += ",";
msg += this.name;
}
msg += "} inited";
LOG.info(msg);
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 3
wjchenge
关注
还未添加个人签名 2018.07.27 加入
还未添加个人简介
评论