文档章节

commons-dbcp 源码解读

 陆大侠
发布于 2015/12/16 19:37
字数 1304
阅读 68
收藏 0

DBCP是一个使用比较广泛的数据库连接池技术,基于apache的common-pool库。

配置:

http://my.oschina.net/robinsonlu/blog/77759

如何使用:

http://my.oschina.net/donghongyu/blog/190494

主要机制如下:

  1. 拥有若干配置,initialSize初始化的连接池大小,maxActive最大,testWhileIdle,validationQuery等等参数保持了连接的有效性。

  2. 当连接池满时,有多种策略。WHEN_EXHAUSTED_BLOCK 是默认的,还可以有使用新的连接,或则抛出异常。

  3. 每次borrow连接时候,从池种获取一个连接,并test这个连接;return同样需要测试这个连接。 连接池构造函数的最后一句,开启了一个timer,周期性调用evict(), 检查和测试池中的连接。


1.  主要暴露的类是 public class BasicDataSource implements DataSource

(这里插一段SPRING的内容,AbstractPlatformTransactionManager implements PlatformTransactionManager

的getTransaction方法,最终会调用到BasicDataSource的getConnection方法。)

BasicDataSource 的代码如下:

protected volatile GenericObjectPool connectionPool = null;  //这个就是连接池了。
protected volatile DataSource dataSource = null;   //通常这是一个PoolingDataSource ,这个对象也hold一个connectionPool对象
。。每个连接池的配置项都会成为一个成员变量。

public Connection getConnection() throws SQLException {   //这是入口方法,最终在连接池里面borrowObject
        return createDataSource().getConnection();        //这里调用到了dataSource的getConnection、
                                                          //返回了一个PoolableConnection,代理了原始的connection
    }
protected synchronized DataSource createDataSource()
        throws SQLException {
        if (closed) {
            throw new SQLException("Data source is closed");
        }

        // Return the pool if we have already created it
        if (dataSource != null) {
            return (dataSource);
        }
        // create factory which returns raw physical connections  //创建connection的工厂
        ConnectionFactory driverConnectionFactory = createConnectionFactory();
        // create a pool for our connections       //创建连接池 connectionPool变量
        createConnectionPool();

        // Set up statement pool, if desired
        GenericKeyedObjectPoolFactory statementPoolFactory = null;
        if (isPoolPreparedStatements()) {
            statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
                        -1, // unlimited maxActive (per key)
                        GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
                        0, // maxWait
                        1, // maxIdle (per key)
                        maxOpenPreparedStatements);
        }

        // Set up the poolable connection factory
        createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);

        // Create and return the pooling data source to manage the connections
        createDataSourceInstance();       //创建成员变量dataSource,通常这是一个PoolingDataSource
        
        try {
            for (int i = 0 ; i < initialSize ; i++) {
                connectionPool.addObject();            //这里初始化了连接池 initialSize 
            }
        } catch (Exception e) {
            throw new SQLNestedException("Error preloading the connection pool", e);
        }
        
        return dataSource;
    }

最后关闭连接的时候,调用了PoolableConnection的close. 将实际的连接归还到连接池。

2. PoolableConnection代码如下:

PoolableConnection继承自DelegatingConnection类。

public class PoolableConnection extends DelegatingConnection {
protected ObjectPool _pool = null;  //

 public synchronized void close() throws SQLException {
        if (_closed) {
            // already closed
            return;
        }

        boolean isUnderlyingConectionClosed;
        try {
            isUnderlyingConectionClosed = _conn.isClosed();
        } catch (SQLException e) {
            try {  //归还给连接池
                _pool.invalidateObject(this); // XXX should be guarded to happen at most once
            } catch(IllegalStateException ise) {
                // pool is closed, so close the connection
                passivate();   //如果池已关闭,则也关闭这个连接
                getInnermostDelegate().close();
            } catch (Exception ie) {
                // DO NOTHING the original exception will be rethrown
            }
            throw (SQLException) new SQLException("Cannot close connection (isClosed check failed)").initCause(e);
        }

        if (!isUnderlyingConectionClosed) {
            // Normal close: underlying connection is still open, so we
            // simply need to return this proxy to the pool
            try {
                _pool.returnObject(this); // XXX should be guarded to happen at most once
            } catch(IllegalStateException e) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch(SQLException e) {
                throw e;
            } catch(RuntimeException e) {
                throw e;
            } catch(Exception e) {
                throw (SQLException) new SQLException("Cannot close connection (return to pool failed)").initCause(e);
            }
        } else {
            // Abnormal close: underlying connection closed unexpectedly, so we
            // must destroy this proxy
            try {
                _pool.invalidateObject(this); // XXX should be guarded to happen at most once
            } catch(IllegalStateException e) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch (Exception ie) {
                // DO NOTHING, "Already closed" exception thrown below
            }
            throw new SQLException("Already closed.");
        }
    }

   3. PoolableConnectionFactory 是创建连接的工厂类。

makeObject方法创建一个Connection实例,并使用PoolableConnection进行了代理。

还有以下方法:passivateObject,activateObject 方法 只是简单的设置了DelegatingConnection的isClosed的值。validateConnection 执行了一条测试的SQL。

public Object makeObject() throws Exception {
        Connection conn = _connFactory.createConnection();
        if (conn == null) {
            throw new IllegalStateException("Connection factory returned null from createConnection");
        }
        initializeConnection(conn);
        if(null != _stmtPoolFactory) {
            KeyedObjectPool stmtpool = _stmtPoolFactory.createPool();
            conn = new PoolingConnection(conn,stmtpool);
            stmtpool.setFactory((PoolingConnection)conn);
        }
        return new PoolableConnection(conn,_pool,_config);
    }

4 . GenericObjectPool 类是连接池的hold的对象。这个类是连接池实现的核心类,但是方法都特别长,描述一下把。

    它拥有一个private子类型Latch,

private CursorableLinkedList _pool = null;  //这个地方保留了连接池的链表

/** Eviction cursor - keeps track of idle object evictor position */
private CursorableLinkedList.Cursor _evictionCursor = null;  链表当前的位置
private LinkedList _allocationQueue = new LinkedList();      等待分配的queue
 
private static final class Latch {
private ObjectTimestampPair _pair;} //这个_pair 会hold一个connection,供调用borrowObject方法返回。

下面描述GenericObjectPool 的主要方法的行为。
//下面这个方法就是从池中借出一个connection。 1。 首先 实例化一个Latch加入到_allocationQueue中,然后调用allocate()方法,取从_pool中分配一个connection,到_allocationQueue。2。判断自己的Latch有没有拿到连接。如果没有拿到按照配置的策略取等待,失败或则新建连接。3 得到连接之后,激活并测试连接。第三步可能跑出异常.
public Object borrowObject(Object key) throws Exception {

这个方法很关键,分配Connection到_allocationQueue的Latch对象中,或则设置为Latch自己去新建
private synchronized void allocate() {

当归还一个对象时调用这个方法,这个方法的主要逻辑在addObjectToPool方法中。1. validateObject这个对象,如果成功,则钝化这个对象。 2. 如果validate成功,就把这个对象加入到 _pool 中。3 失败,则destroyObject。
public void returnObject(Object obj) throws Exception { 
            addObjectToPool(obj, true);

evict这个方法,在连接池初始化的时候,会新建一个timer。 这个方法很关键,如果不进行evict,连接池就无法保持和数据库的长连接。 
这个方法 遍历了_pool中的对象,调用activateObject,validateObject,passivateObject,验证当前的Object的可用性,如果不可用,就移除。
//startEvictor(_timeBetweenEvictionRunsMillis);
public void evict() throws Exception {


© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 54
码字总数 18787
作品 0
浦东
私信 提问
Apache Common-pool2对象池浅析

Apache Common-pool2包提供了一个通用的对象池技术的实现。可以很方便的基于它来实现自己的对象池,比如DBCP和Jedis他们的内部对象池的实现就是依赖于Common-pool2。 对象的创建和销毁在一定...

同明
2016/06/14
210
0
学习apache commons的兴趣小组

我打算commons的源码,大约2-3周读一个组件,并且写用法和源码心得的主题 目前的计划读的顺序如下: Lang Math Primitives BeanUtils Collections Digester IO Configuration Pool DBCP DbU...

笨笨熊
2010/04/10
554
3
Java 用DBCP连接数据库。

DBCP使用说明 http://commons.apache.org/proper/commons-pool/api-2.4.2/org/apache/commons/pool2/PooledObjectFactory.html?is-external=true 代码实例可以参考 http://www.programcreek.......

Oscarfff
2016/03/02
35
0
activemq 5.13.2 jdbc 数据库持久化 异常 找不到驱动程序

配置activemq 5.13.2 数据库持久化的时候,首先将mysql数据库驱动拷贝到activemq 的lib目录下, 然后配置activemq.xml 文件 增加两个配置点: 1, <persistenceAdapter> <jdbcPersistenceAda...

Atom_me
2016/04/18
469
3
Hibernate dbcp连接池使用方法

这里介绍Hibernate dbcp连接池,使用dbcp,开发人员还需要将commons-pool-1.2.jar 和commons-dbcp-1.2.1.jar两个jar包加入到classpath中。 AD: Hibernate有很多值得学习的地方,这里我们主要...

dong.li
2012/04/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Hibernate SQLite方言

以下代码有参考过github上国外某位大佬的,在发文的最新稳定版Hibernate上是可用的,有时间再仔细分析一下 import org.hibernate.dialect.Dialect;import org.hibernate.dialect.function.S...

CHONGCHEN
今天
3
0
CentOS 7 MariaDB搭建主从服务器

本文编写环境为CentOS7。确保关闭SELinux,关闭防火墙或者防打开指定端口。具体信息如下 #master[root@promote ~]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) [r...

白豆腐徐长卿
今天
10
0
介绍python中运算符优先级

下面这个表给出Python的运算符优先级,从最低的优先级(最松散地结合)到最高的优先级(最紧密地结合)。这意味着在一个表达式中,Python会首先计算表中较下面的运算符,然后在计算列在表上部...

问题终结者
今天
3
0
Spring Boot 2.x基础教程:快速入门

简介 在您第1次接触和学习Spring框架的时候,是否因为其繁杂的配置而退却了?在你第n次使用Spring框架的时候,是否觉得一堆反复黏贴的配置有一些厌烦?那么您就不妨来试试使用Spring Boot来让...

程序猿DD
昨天
10
0
SpringSecurity认证流程源码级详解

SpringSecurity认证流程源码级详解 认证流程说明 认证结果如何在多个请求之间共享 获取认证用户信息

chendom
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部