Druid源码分析(四)-- 初始化DataSource3
Druid源码分析(四)-- 初始化DataSource3
连接池
昨天分析了 filter 和 SPI 机制,今天接着往下看源码
// DruidDataSource.java#init()
// 连接池
connections = new DruidConnectionHolder[maxActive];
// 被断开的连接池
evictConnections = new DruidConnectionHolder[maxActive];
// 还正常的连接池
keepAliveConnections = new DruidConnectionHolder[maxActive]
这一段就是数据库连接池的初始化,maxActive是最大连接池数量
DruidConnectionHolder 包装了数据源和真正的数据库连接conn
// DruidConnectionHolder.java
// 数据源
protected final DruidAbstractDataSource dataSource;
// 连接id
protected final long connectionId;
// 数据库连接
protected final Connection conn;
接着往下是连接池的初始化
// 如果是异步初始化,先初始化默认连接数,这个值默认为0
if (createScheduler != null && asyncInit) {
for (int i = 0; i < initialSize; ++i) {
submitCreateTask(true);
}
} else if (!asyncInit) {
// 初始化连接
while (poolingCount < initialSize) {
try {
PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
connections[poolingCount++] = holder;
} catch (SQLException ex) {
...
// 异常就睡眠3s
Thread.sleep(3000);
}
}
...
}
接下来是创建日志线程和Create、Destroy线程,这里用到了CountDownLatch
createAndLogThread();
createAndStartCreatorThread();
createAndStartDestroyThread();
initedLatch.await();
// 默认initedLatch 为2
private final CountDownLatch initedLatch = new CountDownLatch(2);
protected void createAndStartDestroyThread() {
initedLatch.countDown();
...
}
protected void createAndStartCreatorThread() {
...
initedLatch.countDown();
}
CountDownLatch主要有两个方法:countDown()和await()。countDown()方法用于使计数器减一,其一般是执行任务的线程调用,await()方法则使调用该方法的线程处于等待状态,其一般是主线程调用。
接下来就是把初始化标识设置为true ,注册Mbean,添加JMX监控
init = true;
registerMbean();
最后,在finally里把初始化标识设置为true 、解锁,避免死锁
finally {
inited = true;
lock.unlock();
if (init && LOG.isInfoEnabled()) {
String msg = "{dataSource-" + this.getID();
...
msg += "} inited";
LOG.info(msg);
}
然后打印 {dataSource-1} inited
到这里整个 init 函数就完成了
总结
分析了3天的初始化函数,感觉学到了很多,不管是双重校验+锁,还是SPI机制、CountDownLatch等,我在日常项目里都没怎么用过,然后就是为了避免死锁等问题,一定要在finally 里解锁。