使用commons-pool 构筑简易ConnectionPool

  在编程中,池的运用应当是很广泛了,如连接池,线程池,资源池等。实际编程中,我们也可以构建Cache池,也可能有涉及到其它的情况,需要使用pool方案来解决。为此Apache中开发了一个通用的Pool工具:commons-pool,现在这个工具有两个版本(1.X, 2.X)并且有很大的不同。这里说的是Commons-pool 的1.X版本。

本文将分为两个部分,第一部分介绍commons-pool 1.X API。第二部分使用commons-pool构筑简易ConnectionPool。

第一部分Commons-pool 1.X 介绍

下面是commons-pool的设计方案:

总体来看,就是由ObjectPoolFactory创建出ObjectPool,然后在使用ObjectPool的过程中(例如borrowObject(),returnObject()等方法),通过ObjectFactory,来对特定的对象进行处理。

由于官方文档中,对于commons-pool的描述并不多,所以只能看代码来了解了。

如果你的ObjectPool组件都设计完毕,在使用ObjectPool时,入口就是ObjectPool。

下面就看看ObjectPool的说明 :

从这个说明上可以知道,只需要在合适的地方合理的调用borrowObject()、invalidateObject()、returnObject() 对对象进行处理即可。通过源码知道,这几个方法在处理过程中会委托给PoolableObjectFactory来处理,下面就来看看这个接口的设计。

从上面的描述也可以看出:

1、borrowObject时,会先从pool中找出一个idle的对象,如果找不到,就可以使用makeObject()来创建对象,并使用activateObject()将对象设置为active状态。如果找到了对象,不需要调用makeObject(),但是会调用validateObject()。

2、如果一个对象要被抛弃,就可以使用invaliateObejct()将对象设置为无效状态。

3、如果对象正常使用完毕,就应该让对象返回pool中,并将其钝化,也就是设置为idle状态。

通过对commons-pool的了解,应该就可以明白,在使用commons-pool,可以对ObjectPoolFactory、PoolableObjectFactory进行定制,在必要的情况下,也可以对ObjectPool进行定制。

第二部分使用commons-pool构筑简易ConnectionPool

// 定义一个ConnectionPoolFactory,目前中是实现了构建器,其它功能还待完善。

package com.fjn.frame.apache.commons.pool.connectionPool;

import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPoolFactory;

public class ConnectionPoolFactory extends GenericObjectPoolFactory{

    public ConnectionPoolFactory(PoolableObjectFactory factory, int maxActive,
            byte whenExhaustedAction, long maxWait, int maxIdle, int minIdle,
            boolean testOnBorrow, boolean testOnReturn,
            long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun,
            long minEvictableIdleTimeMillis, boolean testWhileIdle,
            long softMinEvictableIdleTimeMillis, boolean lifo) {
        super(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, minIdle,
                testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis,
                numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle,
                softMinEvictableIdleTimeMillis, lifo);
    }

}
package com.fjn.frame.apache.commons.pool.connectionPool;

public class ConnectionInfo {
    ConnectionFactory factory;

    public ConnectionFactory getFactory() {
        return factory;
    }

    public void setFactory(ConnectionFactory factory) {
        this.factory = factory;
    }
}

// 连接工厂

package com.fjn.frame.apache.commons.pool.connectionPool;

import java.sql.DriverManager;

import org.apache.commons.pool.BasePoolableObjectFactory;

public class ConnectionFactory extends BasePoolableObjectFactory{
    private String driverClass;
    private String username;
    private String password;
    private String url;

    public String getDriverClass() {
        return driverClass;
    }

    public void setDriverClass(String driverClass) {
        this.driverClass = driverClass;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    Connection _createConnection() throws Exception{
        Connection connection=null;
        java.sql.Connection conn=null;
        Class.forName(driverClass);
        conn= DriverManager.getConnection(url, username, password);
        connection=new Connection();
        connection.setConn(conn);
        ConnectionInfo connInfo=new ConnectionInfo();
        connInfo.setFactory(this);
        return connection;
    }

    // 只为了测试使用
    private Object createConnection(){
        return new Connection();
    }

    @Override
    public Object makeObject() throws Exception {
        return createConnection();
    }

}

// Connection

package com.fjn.frame.apache.commons.pool.connectionPool;

import java.sql.SQLException;

public class Connection {
    private java.sql.Connection conn;
    private ConnectionInfo connInfo;
    public java.sql.Connection getConn() {
        return conn;
    }
    public void setConn(java.sql.Connection conn) {
        this.conn = conn;
    }
    public ConnectionInfo getConnInfo() {
        return connInfo;
    }
    public void setConnInfo(ConnectionInfo connInfo) {
        this.connInfo = connInfo;
    }

    public void close(){
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

// 测试

package com.fjn.frame.apache.commons.pool.connectionPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;

public class ConnectionManager {
    private ObjectPool pool;
    private ConnectionFactory connFactory;
    private ConnectionPoolFactory connPoolFactory;

    public void initConnectionPool(int maxNum, int maxIdleCount,
            int minIdleCount, long maxWaitTime) {
        int maxActive = maxNum;
        byte whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
        long maxWait = maxWaitTime;
        int maxIdle = maxIdleCount;
        int minIdle = minIdleCount;
        boolean testOnBorrow = GenericObjectPool.DEFAULT_TEST_ON_BORROW;
        boolean testOnReturn = GenericObjectPool.DEFAULT_TEST_ON_RETURN;
        long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
        int numTestsPerEvictionRun = GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
        long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
        boolean testWhileIdle = GenericObjectPool.DEFAULT_TEST_WHILE_IDLE;
        long softMinEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
        boolean lifo = GenericObjectPool.DEFAULT_LIFO;
        connPoolFactory = new ConnectionPoolFactory(connFactory, maxActive,
                whenExhaustedAction, maxWait, maxIdle, minIdle, testOnBorrow,
                testOnReturn, timeBetweenEvictionRunsMillis,
                numTestsPerEvictionRun, minEvictableIdleTimeMillis,
                testWhileIdle, softMinEvictableIdleTimeMillis, lifo);

    }

    public static void main(String[] args) {
        final ConnectionManager mgr = new ConnectionManager();
        mgr.connFactory = new ConnectionFactory();
        mgr.connFactory.setDriverClass("com.mysql.jdbc.Driver");
        mgr.connFactory.setPassword("mysql");
        mgr.connFactory.setUsername("mysql");
        mgr.connFactory.setUrl("url:localhost:3306"); // 改成真实的URL

        mgr.initConnectionPool(1000, 50, 5, 1000 * 60);
        mgr.pool = mgr.connPoolFactory.createPool();

        final AtomicInteger count = new AtomicInteger(0);

        int threadNum = Runtime.getRuntime().availableProcessors();
        ExecutorService client = Executors.newFixedThreadPool(threadNum);
        for (int i = 0; i < threadNum; i++) {
            client.submit(new Runnable() {
                @Override
                public void run() {
                    while (true && count.get() < 100) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e1) {
                            e1.printStackTrace();
                        }
                        Connection connection = null;

                        try {
                            connection = (Connection) mgr.pool.borrowObject();
                            try {

                                int value = count.incrementAndGet();
                                if (value < 100) {
                                    String threadName = Thread.currentThread()
                                            .getName();

                                    int activeNum = mgr.pool.getNumActive();
                                    int idleNum = mgr.pool.getNumIdle();
                                    String content = "ThreadName: "
                                            + threadName
                                            + "\t SQL: "
                                            + "insert into tableA ( ct ) values (‘"
                                            + value + "‘); \t activeNum="
                                            + activeNum + "\t idleNum="
                                            + idleNum;
                                    System.out.println(content);
                                }

                            } catch (Exception e) {
                                mgr.pool.invalidateObject(connection);
                                connection = null;
                            } finally {
                                // make sure the object is returned to the pool
                                if (null != connection) {
                                    mgr.pool.returnObject(connection);
                                }
                            }
                        } catch (Exception e) {
                            // failed to borrow an object
                        }

                    }
                }
            });
        }
    }

}

目前使用这个小程序,应用可以跑起来了,但是它并不是一个真实的连接池实现,需要的工作还有很多。

这个小程序,只是一个commons-pool 1.X的demo ,也只是为了证明我上面的想法,具体如何使用,还需要深入的研究。

时间: 2024-10-21 22:47:04

使用commons-pool 构筑简易ConnectionPool的相关文章

apache commons pool

apache commons下的pool 其中的borrowObject函数源代码显示其产生可用对象的过程: 如果stack中有空闲的对象,则pop对象,激活对象(activate函数),验证对象(validate函数).最终将合格的对象返回给client. 若对象在这个流程中出错,则在从stack中取出一个,并执行相同的流程.如此循环,直到stack为空. 如果stack为空,则直接调用makeObject函数创建一个对象.在返回对象之前,还会调用验证函数(validate)验证是否有效. 转

Cache Lucene IndexReader with Apache Commons Pool

IndexReaderFactory.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package org.ostree.module.lucene; import org.apache.commons.pool.Ke

Apache Commons pool 简介和pool连接池代码

在实际中工作,我们经常遇到需要连接池的地方,特别是数据库连接池. 我们为什么需要池呢?因为这些资源的创建,都很消耗资源.因此,我们使用一个对象池,里面预先创建了一些资源对象.当我们需要时,从池中取出对象,而不需要时,把对象返回池中.这样就可以提高代码运行的效率. Apache Commons Pool(http://commons.apache.org/pool/)为我们提供了很方便的接口来实现对象池.我们唯一需要实现的就是如何产生对象,而不用去考虑一堆多线程问题. 2013年,Apache C

The type org.apache.commons.pool.impl.GenericObjectPool$Config cannot be resolved. It is indirectly

static { try { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxActive(MAX_ACTIVE); config.setMaxIdle(MAX_IDLE); config.setMaxWait(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, A

【Tomcat】【3】报错 Illegal access: this web application instance has been stopped already. Could not load [org.apache.commons.pool.impl.CursorableLinkedList$Cursor]

用Tomcat运行项目报错: Illegal access: this web application instance has been stopped already. Could not load [org.apache.commons.pool.impl.CursorableLinkedList$Cursor]. The following stack trace is thrown for debugging purposes as well as to attempt to term

Apache Commons 工具类介绍及简单使用

Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下面是我这几年做开发过程中自己用过的工具类做简单介绍.   组件 功能介绍 BeanUtils 提供了对于JavaBean进行各种操作,克隆对象,属性等等. Betwixt XML与Java对象之间相互转换. Codec 处理常用的编码方法的工具类包 例如DES.SHA1.MD5.Base64等. Collections java集合框架操作. Compress java提供文件打包 压缩类库. C

Apache Commons 工具集介绍

Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下面是我这几年做开发过程中自己用过的工具类做简单介绍. 组件 功能介绍 BeanUtils 提供了对于JavaBean进行各种操作,克隆对象,属性等等. Betwixt XML与Java对象之间相互转换. Codec 处理常用的编码方法的工具类包 例如DES.SHA1.MD5.Base64等. Collections java集合框架操作. Compress java提供文件打包 压缩类库. Con

Apache Commons工具集简介

Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下面是我这几年做开发过程中自己用过的工具类做简单介绍. 组件 功能介绍 BeanUtils 提供了对于JavaBean进行各种操作,克隆对象,属性等等. Betwixt XML与Java对象之间相互转换. Codec 处理常用的编码方法的工具类包 例如DES.SHA1.MD5.Base64等. Collections java集合框架操作. Compress java提供文件打包 压缩类库. Con

Apache Commons Pool2 源码分析 | Apache Commons Pool2 Source Code Analysis

Apache Commons Pool实现了对象池的功能.定义了对象的生成.销毁.激活.钝化等操作及其状态转换,并提供几个默认的对象池实现.在讲述其实现原理前,先提一下其中有几个重要的对象: PooledObject(池对象). PooledObjectFactory(池对象工厂). Object Pool(对象池). 下面分别详细讲解它们的实现. PooledObject(池对象) 用于封装对象(如:线程.数据库连接.TCP连接),将其包裹成可被池管理的对象.提供了两个默认的池对象实现: De