基於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) {
            }
        }
    }
}

  下面我們看看運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM