Fork me on GitHub

基于Commons-Pool2实现自己的redis连接池

  我们在服务器开发的过程中,往往会有一些对象,它的创建和初始化需要的时间比较长,比如数据库连接,网络IO,大数据对象等。在大量使用这些对象时,如果不采用一些技术优化,就会造成一些不可忽略的性能影响。一种办法就是使用对象池,每次创建的对象并不实际销毁,而是缓存在对象池中,下次使用的时候,不用再重新创建,直接从对象池的缓存中取即可。为了避免重新造轮子,我们可以使用优秀的开源对象池化组件apache-common-pool2,它对对象池化操作进行了很好的封装,我们只需要根据自己的业务需求重写或实现部分接口即可,使用它可以快速的创建一个方便,简单,强大对象连接池管理类。

  下面先看看主要的几个种要的接口和实现类:

  • PooledObjectFactory<T>: 对象工厂,在需要的时候生成新的对象实例,并放入池中,一般使用抽象类BasePooledObjectFactory<T>,在GenericObjectPool中,有两个我们会用到的方法:public Jedis create() throws Exception 创建对象,public PooledObject<T> wrap(T t) 封装为池化对象。其它还有一些方法,可以查看下面的MyJedisFactory代码。
  • ObjectPool: 对象池,用于存储对象,并管理对象的入池和出池。对象池的实现类是 GenericObjectPool<T>;在GenericObjectPool中,有两个我们会用到的方法:public T borrowObject() throws Exception 从对象池中获取一个对象,public void returnObject(T obj) 对象使用完之后,归还到对象池,其它还有一些方法,比如关闭对象池,销毁对象池等。
  • BaseObjectPoolConfig: 池属性,用于设置连接池的一些配置信息,比如最大池容量、超过池容量后的处理逻辑等。池属性的实现类是:GenericObjectPoolConfig;
  • Object: 池对象,由对象工厂负责创建,并放入到对象池中;需要使用时从对象池中取出,执行对象的业务逻辑,使用完后再放回对象池。

  下面我们来用代码实现jedis的连接池,类关系图如下:

  1,引入依赖

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.10.0</version>
        </dependency>
<!-- 下面这个是为了使用jedis,但是我们不用它自带的redisPool -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.1</version>
        </dependency>

  2,创建MyJedisFactory类,继承BasePooledObjectFactory<Jedis>

public class MyJedisFactory extends BasePooledObjectFactory<Jedis> {

    //计数,连接池内的对象个数
    private AtomicInteger sum = new AtomicInteger(0);

    private static String HOST = "******";
    private static int PORT = 6379;
    private static String PASSWORD = "****";
    /**
     * 创造对象
     * @return
     * @throws Exception
     */
    @Override
    public Jedis create() throws Exception {
        System.out.println("创造了  " + sum.incrementAndGet() + "个对象");
        Jedis jedis = new Jedis(HOST, PORT);
        jedis.auth(PASSWORD);
        return jedis;
    }

    /**
     * 破坏对象
     * @param p
     * @throws Exception
     */
    @Override
    public void destroyObject(PooledObject<Jedis> p) throws Exception {
        System.out.println("破坏" );
        super.destroyObject(p);
    }

    /**
     * 封装为池化对象
     * @param jedis
     * @return
     */
    @Override
    public PooledObject<Jedis> wrap(Jedis jedis) {
        return new DefaultPooledObject<Jedis>(jedis);
    }

    /**
     * 拿取时调用
     * @param p
     * @throws Exception
     */
    @Override
    public void activateObject(PooledObject<Jedis> p) throws Exception {
        super.activateObject(p);
        System.out.println("拿取" + sum.get());
    }

    /**
     * 返还池子里时调用
     * @param pooledObject
     * @throws Exception
     */
    @Override
    public void passivateObject(PooledObject<Jedis> pooledObject) throws Exception{
        super.passivateObject(pooledObject);
        System.out.println("返还" + sum.get());
    }

    /**
     *
     * @param p
     * @return
     */
    @Override
    public boolean validateObject(PooledObject<Jedis> p){
        System.out.println("校验" );
        return super.validateObject(p);
    }
}

  3,创建MyJedisPool类,继承GenericObjectPool<Jedis>

public class MyJedisPool extends GenericObjectPool<Jedis> {

    public MyJedisPool(PooledObjectFactory<Jedis> factory) {
        super(factory);
    }

    public MyJedisPool(PooledObjectFactory<Jedis> factory, GenericObjectPoolConfig config) {
        super(factory, config);
    }

    public MyJedisPool(PooledObjectFactory<Jedis> factory, GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) {
        super(factory, config, abandonedConfig);
    }
}

  4,测试testPool类

public class testPool {
    public static void main(String[] args) {
        PooledObjectFactory<Jedis> fac = new MyJedisFactory();
        GenericObjectPool<Jedis> pool = new MyJedisPool(fac,new GenericObjectPoolConfig());
        int testCount = 20;
        CountDownLatch c = new CountDownLatch(testCount);
        for (int i = 0; i < testCount; i++) {
            new Thread(() -> {
                testPool(pool);
                c.countDown();
            }).start();
        }
        try {
            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("活跃数: " + pool.getNumActive());
        System.out.println("空闲数: " + pool.getNumIdle());
    }

    static void testPool(GenericObjectPool<Jedis> pool) {
        Jedis myJedis = null;
        try {
            // 从池中获取对象
            myJedis = pool.borrowObject();
            // 使用对象
            System.out.println(myJedis.get("*********"));
        } catch (Exception e) {
            try {
                // 出现错误将对象置为失效
                pool.invalidateObject(myJedis);
                myJedis = null;
            } catch (Exception ex) {
            }
        } finally {
            try {
                if (null != myJedis) {
                    // 使用完后必须 returnObject
                    pool.returnObject(myJedis);
                }
            } catch (Exception e) {
            }
        }
    }
}

  下面我们看看运行结果:

 

posted @ 2021-12-17 10:33  爱跑步的星仔  阅读(1061)  评论(0编辑  收藏  举报