dbcp removeAbandonedTimeout 详解

字体大小: 中小 标准 ->行高大小: 标准
dbcp源码解析
PoolingDataSource类
public Connection getConnection()
        throws SQLException
    {
        Connection conn;
        conn = (Connection)_pool.borrowObject();//从线程池取连接
        if(conn != null)
            conn = new PoolGuardConnectionWrapper(conn);
        return conn;
        ............................................
    }
AbandonedObjectPool类
    public Object borrowObject() throws Exception {
        if (config != null && config.getRemoveAbandoned() && getNumIdle() < 2
                && getNumActive() > getMaxActive() - 3)//回收连接事件发生的条件
            removeAbandoned();
        Object obj = super.borrowObject();
       .....................
    }
private void removeAbandoned() {
        long now = System.currentTimeMillis();
        long timeout = now - (long) (config.getRemoveAbandonedTimeout() * 1000);
        ArrayList remove = new ArrayList();
        synchronized (trace) {
            Iterator it = trace.iterator();
            do {
                if (!it.hasNext())
                    break;
                AbandonedTrace pc = (AbandonedTrace) it.next();
                if (pc.getLastUsed() <= timeout && pc.getLastUsed() > 0L)//lastUsed是关键
                    remove.add(pc);
            } while (true);
        }
        for (Iterator it = remove.iterator(); it.hasNext();) {
            AbandonedTrace pc = (AbandonedTrace) it.next();
            if (config.getLogAbandoned())
                pc.printStackTrace();
            try {
                invalidateObject(pc);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

// 下面看lastUsed如何变化
GenericObjectPool类 (AbandonedObjectPool的父类)
public Object borrowObject()
        throws Exception
    {
........................
        _factory.activateObject(latch.getPair().value);//激活连接
        if(_testOnBorrow && !_factory.validateObject(latch.getPair().value))
            throw new Exception("ValidateObject failed");
        synchronized(this)
        {
            _numInternalProcessing--;
            _numActive++;
        }
        ..............
    }

PoolableConnectionFactory 类

    public void activateObject(Object obj) throws Exception {
        if (obj instanceof DelegatingConnection)
            ((DelegatingConnection) obj).activate();
      .......................
    }

DelegatingConnection类(DelegatingConnection extends AbandonedTrace implements Connection)

    protected void activate() {
        _closed = false;
        setLastUsed();//lastUsed赋值(当前系统时间)父类AbandonedTrace 中的方法
............................................
    }

    public void close() throws SQLException {//关闭连接时
        passivate();
        _conn.close();
    }
    protected void passivate()
        throws SQLException
    {
        List statements = getTrace();
        if(statements != null)
        {
            Statement set[] = new Statement[statements.size()];
            statements.toArray(set);
            for(int i = 0; i < set.length; i++)
                set[i].close();

            clearTrace();
        }
        setLastUsed(0L);//lastUsed置为0,置为闲置连接
     ...............
    }
分析总结:removeAbandonedTimeout的含义是,在config != null(有配置) && config.getRemoveAbandoned() (removeAbandoned开启)&& getNumIdle()(闲置连接数) < 2
                && getNumActive() (活动连接数)> getMaxActive() - 3)时发起回收事件,
回满足pc.getLastUsed() <= timeout && pc.getLastUsed() > 0L(一直在活动状态,已经超时了)这样条件
的连接,连接从池中取出时lastUsed赋值为当前系统时间,关闭时,lastUsed置为0

补充:
PoolableConnection类(public class PoolableConnection extends DelegatingConnection)
从连接池中取出的连接应该是PoolableConnection的实例
    public synchronized void close() throws SQLException {
        boolean isClosed = false;
        try {
            isClosed = isClosed();
        } catch (SQLException e) {
            try {
                _pool.invalidateObject(this);
            } catch (Exception ie) {
            }
            throw new SQLNestedException(
                    "Cannot close connection (isClosed check failed)", e);
        }
        if (isClosed) {
            try {
                _pool.invalidateObject(this);
            } catch (Exception ie) {
            }
            throw new SQLException("Already closed.");
        }
        try {
            _pool.returnObject(this);
        } catch (SQLException e) {
            throw e;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new SQLNestedException(
                    "Cannot close connection (return to pool failed)", e);
        }
    }

当 removeAbandonedTimeout设的过小,而应用中又有某条sql执行时间过长,就会报Already closed.

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/68245.html