(1)獲取連接方法getConnectionDirect()線程:
這裏是Druid的三個核心線程的交互邏輯圖
⚠️這裏是init();初始化在這一步:主要核心就是創建這幾個線程
createAndLogThread(); //打印日誌線程其實就是統計監控信息
createAndStartCreatorThread(); //創建連接的線程
createAndStartDestroyThread(); //銷燬連接的線程
-
首先第一大步驟就是先去獲取DruidPooledConnection,通過getConnectionInternal()方法
-
進入到方法內:
- 先進行一個for死循環當createDirect = true時跳出循環,首次爲false,所以下一步重要的就是創建ScheduledThreadPoolExecutor 對象,條件就是當:【poolingCount(池子中的值爲0時) && 活躍的連接 < maxActive && createScheduler != null && createScheduler instanceof ScheduledThreadPoolExecutor】 , 然後ScheduledThreadPoolExecutor中的getQueue().size() > 0 時,把createDirect = true,然後繼續往下走,
- 然後通過我們設置的setMaxWait 時間進行判斷,如果MaxWait > 0 ,就會從LRU的隊列中的尾部取出一個connection使用方法 pollLast(nanos); 否則走takeLast();
- 如果DruidConnectionHolder 不爲null ,把【connection】活躍的ActiveCount++,然後跳出循環
- 此時的createDirect = true,所以會去創建一個物理連接 賦值給 DruidConnectionHolder對象
PhysicalConnectionInfo pyConnInfo = DruidDataSource.this.createPhysicalConnection(); holder = new DruidConnectionHolder(this, pyConnInfo);
- 然後加鎖,判斷 activeCount < maxActive ,如果爲True就把活躍的Connection連接進行➕1,跳出循環,如果 activeCount > maxActive,則需要丟棄創建好的這個創建好的物理連接
JdbcUtils.close(pyConnInfo.getPhysicalConnection());
-
如果成功繼續走到下一步
-
如果失敗捕獲住錯誤的話,就繼續嘗試獲取DruidPooledConnection
-
-
然後回到getConnectionDirect()方法中,走到第二個步驟中,先判斷配置參數testOnBorrow是不是爲True,然後去進行對連接進行校驗,如果校驗成功就繼續往下走,
boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn); if (!validate) { Connection realConnection = poolableConnection.conn; discardConnection(realConnection); continue; }
-
如果配置參數testOnBorrow爲True的話會先進行一次上面代碼的校驗,如果testOnBorrow爲False的話,並且 testWhileIdle參數爲True的話,會再進行判斷,如果【timeBetweenEvictionRunsMillis <= 0】直接使用 60s 進行填充
-
繼續走,如果當前連接的空閒時間【idleMillis >= timeBetweenEvictionRunsMillis || idleMillis < 0】時,會繼續進行校驗當前連接的健康情況,和上面代碼一樣,如果校驗不成功就會discard當前的Connection
-
繼續,然後判斷配置參數removeAbandoned是不是爲True,如果是就以當前連接poolableConnection 爲Key,PRESENT作爲Value放到activeConnections的Map集合中
Map<DruidPooledConnection, Object> activeConnections = new IdentityHashMap<DruidPooledConnection, Object>();
//這裏是判斷邏輯
if (removeAbandoned) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
poolableConnection.connectStackTrace = stackTrace;
poolableConnection.setConnectedTimeNano();
poolableConnection.traceEnable = true;
activeConnectionLock.lock();
try {
activeConnections.put(poolableConnection, PRESENT);
} finally {
activeConnectionLock.unlock();
}
}
- 繼續,如果配置的defaultAutoCommit參數是不是爲False,如果爲False,執行,poolableConnection.setAutoCommit(false);
- 最後 getConnectionDirect(long maxWaitMillis)方法 返回DruidPooledConnection 對象 poolableConnection
⚠️這裏補充一下第一大步的第2小步中的pollLast(nanos)和takeLast(nanos)方法中如果沒有從LRU隊列中的尾部獲取到Connection時,就會發送圖中的notify信號,去通知創建連接的線程去創建連接**
建議對照源碼進行分析:
1. 先進入到getConnection方法中
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
init();
if (filters.size() > 0) {
FilterChainImpl filterChain = new FilterChainImpl(this);
return filterChain.dataSource_connect(this, maxWaitMillis);
} else {
return getConnectionDirect(maxWaitMillis);
}
}
- 然後進入到getConnectionDirect()方法中:
public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
int notFullTimeoutRetryCnt = 0;
for (;;) {
// handle notFullTimeoutRetry
DruidPooledConnection poolableConnection;
try {
//這裏的getConnectionInternal方法,其實對應的就是上面分析中的第一大步裏面的邏輯
poolableConnection = getConnectionInternal(maxWaitMillis);
} catch (GetConnectionTimeoutException ex) {
if (notFullTimeoutRetryCnt <= this.notFullTimeoutRetryCount && !isFull()) {
notFullTimeoutRetryCnt++;
if (LOG.isWarnEnabled()) {
LOG.warn("get connection timeout retry : " + notFullTimeoutRetryCnt);
}
continue;
}
throw ex;
}
if (testOnBorrow) {
boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
if (!validate) {
if (LOG.isDebugEnabled()) {
LOG.debug("skip not validate connection.");
}
Connection realConnection = poolableConnection.conn;
discardConnection(realConnection);
continue;
}
} else {
Connection realConnection = poolableConnection.conn;
if (poolableConnection.conn.isClosed()) {
discardConnection(null); // 傳入null,避免重複關閉
continue;
}
if (testWhileIdle) {
final DruidConnectionHolder holder = poolableConnection.holder;
long currentTimeMillis = System.currentTimeMillis();
long lastActiveTimeMillis = holder.lastActiveTimeMillis;
long lastKeepTimeMillis = holder.lastKeepTimeMillis;
if (lastKeepTimeMillis > lastActiveTimeMillis) {
lastActiveTimeMillis = lastKeepTimeMillis;
}
long idleMillis = currentTimeMillis - lastActiveTimeMillis;
long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;
if (timeBetweenEvictionRunsMillis <= 0) {
timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
}
if (idleMillis >= timeBetweenEvictionRunsMillis
|| idleMillis < 0 // unexcepted branch
) {
boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
if (!validate) {
if (LOG.isDebugEnabled()) {
LOG.debug("skip not validate connection.");
}
discardConnection(realConnection);
continue;
}
}
}
}
if (removeAbandoned) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
poolableConnection.connectStackTrace = stackTrace;
poolableConnection.setConnectedTimeNano();
poolableConnection.traceEnable = true;
activeConnectionLock.lock();
try {
activeConnections.put(poolableConnection, PRESENT);
} finally {
activeConnectionLock.unlock();
}
}
if (!this.defaultAutoCommit) {
poolableConnection.setAutoCommit(false);
}
return poolableConnection;
}
}
參考文章:http://zhengjianglong.cn/2019/07/14/framework/druid-db-connection/