数据库连接池 -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();// 初始化ValidConnectionCheckerinitValidConnectionChecker();// 检查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 加入
还未添加个人简介










评论