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();

  }

  }

  }