zoukankan      html  css  js  c++  java
  • 基于CommonsPool2实现自己的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) {
                }
            }
        }
    }

      下面我们看看运行结果:

     

    身体是革命的本钱,爱跑步,爱生活!
  • 相关阅读:
    outlook配置其他邮箱登录如qq邮箱或登录无邮件信息记录
    数据库有自增字段插入数据报错 “列名或所提供值的数目与表定义不匹配。”解决方法
    asp.net编译中出现 数据库 'C:Program FilesMicrosoft SQL ServerMSSQL10_50.MSSQLSERVERMSSQLDATA est1.mdf' 已存在。请选择其他数据库名称。
    SQL使用UPDATE和SUBSTRING截取字符串方法,从头截取到某个位置,截取中间片段,字符串中间截取到末尾或删除前面的字符串
    SQL使用UPDATE和SUBSTRING截取字符串方法,从头截取到某个位置,截取中间片段,字符串中间截取到末尾或删除前面的字符串
    ASP.NET使用window.event.keycode来获取按下的键盘值!
    关于QPS、TPS、PV、UV、GMV、IP、RPS的名词解释!
    java冒泡排序
    java快速获取数组中第二大的数
    java阶乘
  • 原文地址:https://www.cnblogs.com/caozx/p/14845823.html
Copyright © 2011-2022 走看看