源碼分析Jedis配置的TestOnBorrow實現原理及對應的lettuce配置

概述

Jedis的設置項中有一個testOnBorrow的配置項,這個配置項其實來自於Apache CommonPools,意思是從連接池中取出是檢查連接是否失活。

最近需要把項目中的Redis客戶端從Jedis切換成Lettuce,發現Lettuce中沒有testOnBorrow的這個配置項,倒是有一個pingBeforeActivateConnection配置項(官方說法是在使用連接前,先進行PING檢查連接),本着遷移時不對項目現有配置做改動的原則,研究下Jedis的testOnBorrow配置項的底層實現。

步驟

藉助IDEA來進行源碼探索,maven下載包的同時要下載源碼文件

  1. 設置是利用JedisPoolConfig的setTestOnBorrow(boolean)來設置的。於是跳轉到this.testOnBorrow變量。
public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
}
  1. 對testOnBorrow變量利用Alt+F7快捷鍵反查所有用到的地方,查看變量被讀取的地方,可以發現org.apache.commons.pool2.impl.BaseGenericObjectPool.setConfig這裏獲取了變量並利用setTestOnBorrow設置進自身的testOnBorrow變量。

在這裏插入圖片描述

  1. 反查BaseGenericObjectPool中的testOnBorrow變量所有用到的地方,重點看變量的讀取,於是可以發現org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(long)這個方法用到了該變量。其中,關鍵源碼如下:
if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
    boolean validate = false;
    Throwable validationThrowable = null;
    try {
        validate = factory.validateObject(p);
    } catch (Throwable t) {
        PoolUtils.checkRethrow(t);
        validationThrowable = t;
    }
    if (!validate) {
        try {
            destroy(p);
            destroyedByBorrowValidationCount.incrementAndGet();
        } catch (Exception e) {
            // Ignore - validation failure is more important
        }
        p = null;
        if (create) {
            NoSuchElementException nsee = new NoSuchElementException(
                    "Unable to validate object");
            nsee.initCause(validationThrowable);
            throw nsee;
        }
    }
}
  1. 可以發現validate = factory.validateObject(p);這個是關鍵點,在這裏,池化對象p被校驗。
  2. 查看validateObject()的實現,可以發現有多個實現,我們選擇Jedis的實現(即:redis.clients.jedis.JedisFactory.validateObject)
  3. 答案在此揭曉:jedis.ping().equals("PONG"),最終實現採用Redis提供的PING功能實現,對比PING後是否返回PONG來檢查連接是否有效。
  public boolean validateObject(PooledObject<Jedis> pooledJedis) {
    final BinaryJedis jedis = pooledJedis.getObject();
    try {
      HostAndPort hostAndPort = this.hostAndPort.get();

      String connectionHost = jedis.getClient().getHost();
      int connectionPort = jedis.getClient().getPort();

      return hostAndPort.getHost().equals(connectionHost)
          && hostAndPort.getPort() == connectionPort && jedis.isConnected()
          && jedis.ping().equals("PONG"); // 關鍵點
    } catch (final Exception e) {
      return false;
    }
  }

結論

Jedis的testOnBorrow配置項實現原理就是從連接池獲取連接時,利用Redis提供的PING命令來檢查連接是否可用。這個配置類似於Lettuce的pingBeforeActivateConnection配置項。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章