本文将从源码出发详解tomcat jdbc连接池的初始化过程,看下连接池初始化到底做了些什么
代码语言:javascript复制 //创建连接池
public ConnectionPool(PoolConfiguration prop) throws SQLException {
//初始化连接池
init(prop);
}
protected void init(PoolConfiguration properties) throws SQLException {
poolProperties = properties;
//校验连接池配置参数
checkPoolConfiguration(properties);
//make space for 10 extra in case we flow over a bit
busy = new LinkedBlockingQueue<>();
//busy = new FairBlockingQueue<PooledConnection>();
//make space for 10 extra in case we flow over a bit
if (properties.isFairQueue()) {
idle = new FairBlockingQueue<>();
//idle = new MultiLockFairBlockingQueue<PooledConnection>();
//idle = new LinkedTransferQueue<PooledConnection>();
//idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
} else {
idle = new LinkedBlockingQueue<>();
}
//初始化PoolCleaner,该类是一个TimerTask,在定期任务内会执行checkAbandoned、checkIdle、testAllIdle等任务,详情可以参考https://mp.csdn.net/postedit/99671525
initializePoolCleaner(properties);
//create JMX MBean
if (this.getPoolProperties().isJmxEnabled()) createMBean();
//Parse and create an initial set of interceptors. Letting them know the pool has started.
//These interceptors will not get any connection.
PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
for (int i=0; i<proxies.length; i ) {
try {
if (log.isDebugEnabled()) {
log.debug("Creating interceptor instance of class:" proxies[i].getInterceptorClass());
}
JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
interceptor.setProperties(proxies[i].getProperties());
interceptor.poolStarted(this);
}catch (Exception x) {
log.error("Unable to inform interceptor of pool start.",x);
if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
close(true);
SQLException ex = new SQLException();
ex.initCause(x);
throw ex;
}
}
//用initialSize初始化线程池
PooledConnection[] initialPool = new PooledConnection[poolProperties.getInitialSize()];
try {
for (int i = 0; i < initialPool.length; i ) {
//创建连接,创建的连接会被加入到busy队列
initialPool[i] = this.borrowConnection(0, null, null); //don't wait, should be no contention
} //for
} catch (SQLException x) {
log.error("Unable to create initial connections of pool.", x);
if (!poolProperties.isIgnoreExceptionOnPreLoad()) {
if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
close(true);
throw x;
}
} finally {
//返回创建的初始化连接到idle队列中
for (int i = 0; i < initialPool.length; i ) {
if (initialPool[i] != null) {
try {this.returnConnection(initialPool[i]);}catch(Exception x){/*NOOP*/}
} //end if
} //for
} //catch
closed = false;
}
如上述代码所示tomcat jdbc连接池初始化做了以下工作:
1.检查连接池配置属性
2.初始化连接池任务(创建PoolCleaner)
3、根据initialSize创建PoolConnection数组,然后放入到idle队列中,这样从连接池获取数据库连接的时候就可以先使用idle队列中连接,如果idle连接没有可用连接则会判断当前连接池大小是否超过连接池配置的maxActive,如果没有则创建新的数据库连接,否则就会阻塞等待获取到连接为止(当前不是无条件等待,会有一个超时时间-根据连接池maxWait来定)!