Druid之连接创建及销毁示例详解
// checkTime参数表示在将一个连接进行销毁前,是否需要判断一下空闲时间
public void shrink(boolean checkTime, boolean keepAlive) {
// 加锁
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}
// needFill = keepAlive && poolingCount + activeCount < minIdle
// needFill为true时,会调用empty.signal()唤醒生产连接的线程来生产连接
boolean needFill = false;
// evictCount记录需要销毁的连接数
// keepAliveCount记录需要保活的连接数
int evictCount = 0;
int keepAliveCount = 0;
int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;
fatalErrorCountLastShrink = fatalErrorCount;
try {
if (!inited) {
return;
}
// checkCount = 池中已有连接数 - 最小空闲连接数
// 正常情况下,最多能够将前checkCount个连接进行销毁
final int checkCount = poolingCount - minIdle;
final long currentTimeMillis = System.currentTimeMillis();
// 正常情况下,需要遍历池中所有连接
// 从前往后遍历,i为数组索引
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder connection = connections[i];
// 如果发生了致命错误(onFatalError == true)且致命错误发生时间(lastFatalErrorTimeMillis)在连接建立时间之后
// 把连接加入到保活连接数组中
if ((onFatalError || fatalErrorIncrement > 0)
&& (lastFatalErrorTimeMillis > connection.connectTimeMillis)) {
keepAliveConnections[keepAliveCount++] = connection;
continue;
}
if (checkTime) {
// phyTimeoutMillis表示连接的物理存活超时时间,默认值是-1
if (phyTimeoutMillis > 0) {
// phyConnectTimeMillis表示连接的物理存活时间
long phyConnectTimeMillis = currentTimeMillis
- connection.connectTimeMillis;
// 连接的物理存活时间大于phyTimeoutMillis,则将这个连接放入evictConnections数组
if (phyConnectTimeMillis > phyTimeoutMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
// idleMillis表示连接的空闲时间
long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
// minEvictableIdleTimeMillis表示连接允许的最小空闲时间,默认是30分钟
// keepAliveBetweenTimeMillis表示保活间隔时间,默认是2分钟
// 如果连接的空闲时间小于minEvictableIdleTimeMillis且还小于keepAliveBetweenTimeMillis
// 则connections数组中当前连接之后的连接都会满足空闲时间小于minEvictableIdleTimeMillis且还小于keepAliveBetweenTimeMillis
// 此时跳出遍历,不再检查其余的连接
if (idleMillis < minEvictableIdleTimeMillis
&& idleMillis < keepAliveBetweenTimeMillis
) {
break;
}
// 连接的空闲时间大于等于允许的最小空闲时间
if (idleMillis >= minEvictableIdleTimeMillis) {
if (checkTime && i < checkCount) {
// i < checkCount这个条件的理解如下:
// 每次shrink()方法执行时,connections数组中只有索引0到checkCount-1的连接才允许被销毁
// 这样才能保证销毁完连接后,connections数组中至少还有minIdle个连接
evictConnections[evictCount++] = connection;
continue;
} else if (idleMillis > maxEvictableIdleTimeMillis) {
// 如果空闲时间过久,已经大于了允许的最大空闲时间(默认7小时)
// 那么无论如何都要销毁这个连接
evictConnections[evictCount++] = connection;
continue;
}
}
// 如果开启了保活机制,且连接空闲时间大于等于了保活间隔时间
// 此时将连接加入到保活连接数组中
if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
keepAliveConnections[keepAliveCount++] = connection;
}
} else {
// checkTime为false,那么前checkCount个连接直接进行销毁,不再判断这些连接的空闲时间是否超过阈值
if (i < checkCount) {
evictConnections[evictCount++] = connection;
} else {
break;
}
}
}
// removeCount = 销毁连接数 + 保活连接数
// removeCount表示本次从connections数组中拿掉的连接数
// 注:一定是从前往后拿,正常情况下最后minIdle个连接是安全的
int removeCount = evictCount + keepAliveCount;
if (removeCount > 0) {
// [0, 1, 2, 3, 4, null, null, null] -> [3, 4, 2, 3, 4, null, null, null]
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
// [3, 4, 2, 3, 4, null, null, null] -> [3, 4, null, null, null, null, null, null, null]
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
// 更新池中连接数
poolingCount -= removeCount;
}
keepAliveCheckCount += keepAliveCount;
// 如果池中连接数加上活跃连接数(借出去的连接)小于最小空闲连接数
// 则将needFill设为true,后续需要唤醒生产连接的线程来生产连接
if (keepAlive && poolingCount + activeCount < minIdle) {
needFill = true;
}
} finally {
lock.unlock();
}
if (evictCount > 0) {
// 遍历evictConnections数组,销毁其中的连接
for (int i = 0; i < evictCount; ++i) {
DruidConnectionHolder item = evictConnections[i];
Connection connection = item.getConnection();
JdbcUtils.close(connection);
destroyCountUpdater.incrementAndGet(this);
}
Arrays.fill(evictConnections, null);
}
if (keepAliveCount > 0) {
// 遍历keepAliveConnections数组,对其中的连接做可用性校验
// 校验通过连接就放入connections数组,没通过连接就销毁
for (int i = keepAliveCount - 1; i >= 0; --i) {
DruidConnectionHolder holer = keepAliveConnections[i];
Connection connection = holer.getConnection();
holer.incrementKeepAliveCheckCount();
boolean validate = false;
try {
this.validateConnection(connection);
validate = true;
} catch (Throwable error) {
if (LOG.isDebugEnabled()) {
LOG.debug("keepAliveErr", error);
}
}
boolean discard = !validate;
if (validate) {
holer.lastKeepTimeMillis = System.currentTimeMillis();
boolean putOk = put(holer, 0L, true);
if (!putOk) {
discard = true;
}
}
if (discard) {
try {
connection.close();
} catch (Exception e) {
}
lock.lock();
try {
discardCount++;
if (activeCount + poolingCount <= minIdle) {
emptySignal();
}
} finally {
lock.unlock();
}
}
}
this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
Arrays.fill(keepAliveConnections, null);
}
// 如果needFill为true则唤醒生产连接的线程来生产连接
if (needFill) {
lock.lock();
try {
// 计算需要生产连接的个数
int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);
for (int i = 0; i < fillCount; ++i) {
emptySignal();
}
} finally {
lock.unlock();
}
} else if (onFatalError || fatalErrorIncrement > 0) {
lock.lock();
try {
emptySignal();
} finally {
lock.unlock();
}
}
}