前几天把 init 初始化方法大概分析了下,今天继续,把获取连接的部分分析完。
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:(这里入参 maxWaitMillis 默认值为 -1)
public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
int notFullTimeoutRetryCnt = 0;
for (;;) {
// handle notFullTimeoutRetry
DruidPooledConnection poolableConnection;
try {
// 获取连接
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;
}
...
getConnectionInternal 方法前面一些异常场景的判断,最后会走到如下代码处:
if (maxWait > 0) {
holder = pollLast(nanos);
} else {
holder = takeLast();
}
入参为-1,进入 else 分支。
takeLast 通过名字可以得知,应该是从数组最后面获取。
DruidConnectionHolder takeLast() throws InterruptedException, SQLException {
try {
while (poolingCount == 0) {
emptySignal(); // send signal to CreateThread create connection
if (failFast && isFailContinuous()) {
throw new DataSourceNotAvailableException(createError);
}
notEmptyWaitThreadCount++;
if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) {
notEmptyWaitThreadPeak = notEmptyWaitThreadCount;
}
try {
notEmpty.await(); // signal by recycle or creator
} finally {
notEmptyWaitThreadCount--;
}
notEmptyWaitCount++;
if (!enable) {
connectErrorCountUpdater.incrementAndGet(this);
if (disableException != null) {
throw disableException;
}
throw new DataSourceDisableException();
}
}
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
notEmptySignalCount++;
throw ie;
}
进到代码里,显示一个 while 循环,第一个方法是 emptySignal(); 并且有注释: // send signal to CreateThread create connection,向创建线程发送信号去创建连接。
private void emptySignal() {
if (createScheduler == null) {
// 通知创建连接线程继续执行
empty.signal();
return;
}
// 如果创建任务数量大于等于最大创建任务数量,返回
if (createTaskCount >= maxCreateTaskCount) {
return;
}
// 如果活动数量+线程池内数量+创建线程数量大于等于最大活跃数,返回
if (activeCount + poolingCount + createTaskCount >= maxActive) {
return;
}
// 如果前面的分支都没进,代表需要创建任务,并且与初始化时创建任务区分
submitCreateTask(false);
}
默认 createScheduler 是没有设置值的,为null。
看到 empty.sinal() 方法,想到 CreateConnectionThread 创建连接线程的 run() 方法中,2处 empty.await(); 就是要通知在 empty 条件上等待的创建连接线程继续向下执行。
if (emptyWait) {
// 必须存在线程等待,才创建连接
if (poolingCount >= notEmptyWaitThreadCount //
&& (!(keepAlive && activeCount + poolingCount < minIdle))
&& !isFailContinuous()
) {
empty.await();
}
// 防止创建超过maxActive数量的连接
if (activeCount + poolingCount >= maxActive) {
empty.await();
continue;
}
}
最后,返回数组的最后一个 DruidConnectionHolder,并把连接池数量减1,连接池数组置空:
decrementPoolingCount();
DruidConnectionHolder last = connections[poolingCount];
connections[poolingCount] = null;
return last;
返回后,封装到 DruidPooledConnection 中返回:
DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder);
return poolalbeConnection;
后续还做了一些校验,最终返回给调用方。

本文详细分析了Druid连接池获取连接的实现,包括当存在过滤器和无过滤器的情况。在无过滤器时,直接调用getConnectionDirect方法,该方法涉及了连接池的等待、超时重试以及takeLast方法,用于从连接池尾部获取连接。同时,emptySignal方法用于向创建连接线程发送信号,触发创建新的连接。整个过程展示了Druid在高并发下的连接管理和线程同步策略。
5514

被折叠的 条评论
为什么被折叠?



