源码分析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变量。

源码分析Jedis配置的TestOnBorrow实现原理及对应的lettuce配置_第1张图片

  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配置项。

你可能感兴趣的:(Java,源码分析)