版本
Druid: 1.2.5
主流程分析
作为一个数据库连接池,核心功能就是池化连接,而作为使用者,用户从池子中申请连接,完成数据库操作,不用去关心申请连接,销毁连接,池化连接的具体细节。
JDK的javax.sql包的DataSource接口定义了数据源的核心操作
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password) throws SQLException;
Druid的源码中使用了JUC包中的同步组件
使用了ReentrantLock以及Condition来同步协调,用户线程,创建连接线程,销毁连接线程的协作
核心基本集中在DruidDataSource类中,比较重要的四个过程
- 初始化数据库连接池:init方法
- 用户线程获取连接:DruidPooledConnection getConnection()
- 创建连接线程:CreateConnectionThread
- 清理连接线程:DestroyConnectionThread
DruidDataSource继承自DruidAbstractDataSource,DruidAbstractDataSource的构造方法指定了传入锁的类型,并且创建了两个condition
public DruidAbstractDataSource(boolean lockFair){
lock = new ReentrantLock(lockFair);
// 用于用户线程阻塞等待,通知用户线程有可用连接
notEmpty = lock.newCondition();
// 用于创建连接线程阻塞等待,通知创建连接线程创建
empty = lock.newCondition();
}
一张简图大概梳理了关系
初始化过程
public void init() throws SQLException {
if (inited) {
return;
}
// bug fixed for dead lock, for issue #2980
DruidDriver.getInstance();
final ReentrantLock lock = this.lock;
try {
// lock是个可重入锁,加锁
lock.lockInterruptibly();
} catch (InterruptedException e) {
throw new SQLException("interrupt", e);
}
boolean init = false;
try {
// 如果初始化过了,直接返回
if (inited) {
return;
}
// filters初始化
for (Filter filter : filters) {
filter.init(this);
}
// load filters from SPI ServiceLoader
initFromSPIServiceLoader();
// 处理driver,实例化driver
resolveDriver();
// 做一些检查
initCheck();
// 初始化exceptionSorter
initExceptionSorter();
// ValidConnectionChecker
initValidConnectionChecker();
// 做validationQuery检查
validationQueryCheck();
// 持有连接的数组
connections = new DruidConnectionHolder[maxActive];
// 要清除的连接
evictConnections = new DruidConnectionHolder[maxActive];
// 保活的连接
keepAliveConnections = new DruidConnectionHolder[maxActive];
SQLException connectError = null;
if (createScheduler != null && asyncInit) {
for (int i = 0; i < initialSize; ++i) {
submitCreateTask(true);
}
} else if (!asyncInit) {
// init connections,先创建initialSize个连接
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);
}
}
}
if (poolingCount > 0) {
poolingPeak = poolingCount;
poolingPeakTime = System.currentTimeMillis();
}
}
// 创建写日志线程并启动,线程前缀:Druid-ConnectionPool-Log-
createAndLogThread();
// 创建连接线程 线程前缀:Druid-ConnectionPool-Create-
createAndStartCreatorThread();
// 销毁连接线程 定时触发或者Druid-ConnectionPool-Destroy-
createAndStartDestroyThread();
/** 等待 创建连接线程 和 销毁连接线程 全部开启才算初始化完成 */
initedLatch.await();
if (keepAlive) {
// async fill to minIdle
if (createScheduler != null) {
for (int i = 0; i < minIdle; ++i) {
submitCreateTask(true);
}
} else {
this.emptySignal();
}
}
} catch (SQLException e) {
...
} finally {
// 设置标志
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);
}
}
}
获取连接过程
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
// 先尝试初始化,如果初始化过了就返回
init();
// 如果有filter,应用filter链条,最后调用getConnectionDirect
if (filters.size() > 0) {
FilterChainImpl filterChain = new FilterChainImpl(this);
return filterChain.dataSource_connect(this, maxWaitMillis);
} else {
return getConnectionDirect(maxWaitMillis);
}
}
创建连接线程
public class CreateConnectionThread extends Thread {
public CreateConnectionThread(String name){
super(name);
this.setDaemon(true);
}
public void run() {
initedLatch.countDown();
long lastDiscardCount = 0;
int errorCount = 0;
// 死循环
for (;;) {
// addLast
try {
lock.lockInterruptibly();
} catch (InterruptedException e2) {
break;
}
long discardCount = DruidDataSource.this.discardCount;
boolean discardChanged = discardCount - lastDiscardCount > 0;
lastDiscardCount = discardCount;
try {
boolean emptyWait = true;
if (createError != null
&& poolingCount == 0
&& !discardChanged) {
emptyWait = false;
}
if (emptyWait
&& asyncInit && createCount < initialSize) {
emptyWait = false;
}
if (emptyWait) {
// 必须存在线程等待,才创建连接
if (poolingCount >= notEmptyWaitThreadCount //
&& (!(keepAlive && activeCount + poolingCount < minIdle))
&& !isFailContinuous()
) {
empty.await(); // 等待创建连接线程通知
}
// 激活的+池中的不能比max大
// 防止创建超过maxActive数量的连接
if (activeCount + poolingCount >= maxActive) {
empty.await(); // 等待创建连接线程通知
continue;
}
}
} catch (InterruptedException e) {
lastCreateError = e;
lastErrorTimeMillis = System.currentTimeMillis();
if (!closing) {
LOG.error("create connection Thread Interrupted, url: " + jdbcUrl, e);
}
break;
} finally {
lock.unlock();
}
PhysicalConnectionInfo connection = null;
try {
// 真正创建连接
connection = createPhysicalConnection();
} catch (SQLException e) {
LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode()
+ ", state " + e.getSQLState(), e);
errorCount++;
if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
// fail over retry attempts
setFailContinuous(true);
if (failFast) {
lock.lock();
try {
notEmpty.signalAll();
} finally {
lock.unlock();
}
}
// 这里如果配置了true就会退出for
if (breakAfterAcquireFailure) {
break;
}
try {
// 睡timeBetweenConnectErrorMillis
Thread.sleep(timeBetweenConnectErrorMillis);
} catch (InterruptedException interruptEx) {
break;
}
}
} catch (RuntimeException e) {
LOG.error("create connection RuntimeException", e);
setFailContinuous(true);
continue;
} catch (Error e) {
LOG.error("create connection Error", e);
setFailContinuous(true);
break;
}
if (connection == null) {
continue;
}
// 把连接放到池子中
boolean result = put(connection);
if (!result) {
JdbcUtils.close(connection.getPhysicalConnection());
LOG.info("put physical connection to pool failed.");
}
errorCount = 0; // reset errorCount
if (closing || closed) {
break;
}
}
}
}
清理连接线程
public void run() {
initedLatch.countDown();
for (;;) {
// 从前面开始删除
try {
if (closed) {
break;
}
if (timeBetweenEvictionRunsMillis > 0) {
Thread.sleep(timeBetweenEvictionRunsMillis);
} else {
Thread.sleep(1000); //
}
if (Thread.interrupted()) {
break;
}
// 调shrink
destroyTask.run();
} catch (InterruptedException e) {
break;
}
}
}
具体逻辑在shrink方法
-
销毁空闲连接
- 当一个连接长时间没有被使用,如果不及时清理就会造成资源浪费,所以需要定时检查空闲时间过长的连接进行断开连接销毁
-
回收超时连接
- 当一个连接被一个线程长时间占有没有被归还,有可能是程序出故障了或是有漏洞导致没有归还连接,这样就可能会导致连接池中的连接不够用,所以需要定时检查占用连接时间过长的线程,如果超过规定时间没有归还连接,则强制回收该连接。