聊聊jedis連線池對commons-pool的封裝

發表於2023-09-21

文字主要研究一下jedis連線池對commons-pool的封裝

JedisPoolConfig

jedis-3.8.0-sources.jar!/redis/clients/jedis/JedisPoolConfig.java

public class JedisPoolConfig extends GenericObjectPoolConfig<Jedis> {
  public JedisPoolConfig() {
    // defaults to make your life with connection pool easier :)
    setTestWhileIdle(true);
    setMinEvictableIdleTimeMillis(60000);
    setTimeBetweenEvictionRunsMillis(30000);
    setNumTestsPerEvictionRun(-1);
  }
}
JedisPoolConfig繼承了GenericObjectPoolConfig,在構造器裡頭設定了預設的引數,即testWhileIdle為true,minEvictableIdleTime為60s,timeBetweenEvictionRuns為30s,numTestsPerEvictionRun為-1

JedisFactory

見上一篇文章聊聊JedisFactory

Pool

jedis-3.8.0-sources.jar!/redis/clients/jedis/util/Pool.java

public abstract class Pool<T> implements Closeable {

  /**
   * @deprecated This will be private in future.
   */
  @Deprecated
  protected GenericObjectPool<T> internalPool;

  public Pool(final GenericObjectPoolConfig<T> poolConfig, PooledObjectFactory<T> factory) {
    initPool(poolConfig, factory);
  }

  /**
   * @param poolConfig
   * @param factory
   * @deprecated This method will be private in future.
   */
  @Deprecated
  public void initPool(final GenericObjectPoolConfig<T> poolConfig, PooledObjectFactory<T> factory) {

    if (this.internalPool != null) {
      try {
        closeInternalPool();
      } catch (Exception e) {
      }
    }

    this.internalPool = new GenericObjectPool<>(factory, poolConfig);
  }

  public T getResource() {
    try {
      return internalPool.borrowObject();
    } catch (NoSuchElementException nse) {
      if (null == nse.getCause()) { // The exception was caused by an exhausted pool
        throw new JedisExhaustedPoolException(
            "Could not get a resource since the pool is exhausted", nse);
      }
      // Otherwise, the exception was caused by the implemented activateObject() or ValidateObject()
      throw new JedisException("Could not get a resource from the pool", nse);
    } catch (Exception e) {
      throw new JedisConnectionException("Could not get a resource from the pool", e);
    }
  }

  public void returnResource(final T resource) {
    if (resource != null) {
      returnResourceObject(resource);
    }
  }

  /**
   * @param resource
   * @deprecated This will be removed in next major release. Use {@link Pool#returnResource(java.lang.Object)}.
   */
  @Deprecated
  protected void returnResourceObject(final T resource) {
    try {
      internalPool.returnObject(resource);
    } catch (RuntimeException e) {
      throw new JedisException("Could not return the resource to the pool", e);
    }
  }

  public void destroy() {
    closeInternalPool();
  }

/**
   * @deprecated This will be removed in next major release. Use {@link Pool#destroy()}.
   */
  @Deprecated
  protected void closeInternalPool() {
    try {
      internalPool.close();
    } catch (RuntimeException e) {
      throw new JedisException("Could not destroy the pool", e);
    }
  }

  /**
   * @param resource
   * @deprecated This will be removed in next major release. Use {@link Pool#returnBrokenResource(java.lang.Object)}.
   */
  @Deprecated
  protected void returnBrokenResourceObject(final T resource) {
    try {
      internalPool.invalidateObject(resource);
    } catch (Exception e) {
      throw new JedisException("Could not return the broken resource to the pool", e);
    }
  }

  //......
}  
Pool宣告實現Closeable介面,它的構造器根據GenericObjectPoolConfig和PooledObjectFactory來建立GenericObjectPool,它的getResource、returnResource、returnBrokenResourceObject、destroy方法內部都是委託給了GenericObjectPool
它有一個實現類JedisPoolAbstract,而JedisPoolAbstract還有兩個子類,分別是JedisPool、JedisSentinelPool

JedisPoolAbstract

jedis-3.8.0-sources.jar!/redis/clients/jedis/JedisPoolAbstract.java

/**
 * @deprecated This class will be removed in future. If you are directly manipulating this class,
 * you are suggested to change your code to use {@link Pool Pool&lt;Jedis&gt;} instead.
 */
@Deprecated
public class JedisPoolAbstract extends Pool<Jedis> {

  /**
   * Using this constructor means you have to set and initialize the internalPool yourself.
   *
   * @deprecated This constructor will be removed in future.
   */
  @Deprecated
  public JedisPoolAbstract() {
    super();
  }

  public JedisPoolAbstract(GenericObjectPoolConfig<Jedis> poolConfig,
      PooledObjectFactory<Jedis> factory) {
    super(poolConfig, factory);
  }
}
這個類未來將要被廢棄,它主要是設定了Pool的泛型為Jedis

JedisPool

jedis-3.8.0-sources.jar!/redis/clients/jedis/JedisPool.java

public class JedisPool extends JedisPoolAbstract {

  //......

  @Override
  public Jedis getResource() {
    Jedis jedis = super.getResource();
    jedis.setDataSource(this);
    return jedis;
  }

  @Override
  public void returnResource(final Jedis resource) {
    if (resource != null) {
      try {
        resource.resetState();
        returnResourceObject(resource);
      } catch (RuntimeException e) {
        returnBrokenResource(resource);
        log.warn("Resource is returned to the pool as broken", e);
      }
    }
  }
}  
JedisPool覆蓋了getResource和returnResource方法,其中getResource新增了設定dataSource給jedis;returnResource方法新增了jedis的resetState操作,return有異常的話會執行returnBrokenResource

JedisSentinelPool

jedis-3.8.0-sources.jar!/redis/clients/jedis/JedisSentinelPool.java

public class JedisSentinelPool extends JedisPoolAbstract {

  @Override
  public Jedis getResource() {
    while (true) {
      Jedis jedis = super.getResource();
      jedis.setDataSource(this);

      // get a reference because it can change concurrently
      final HostAndPort master = currentHostMaster;
      final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient()
          .getPort());

      if (master.equals(connection)) {
        // connected to the correct master
        return jedis;
      } else {
        returnBrokenResource(jedis);
      }
    }
  }

  @Override
  public void returnResource(final Jedis resource) {
    if (resource != null) {
      try {
        resource.resetState();
        returnResourceObject(resource);
      } catch (RuntimeException e) {
        returnBrokenResource(resource);
        log.debug("Resource is returned to the pool as broken", e);
      }
    }
  }

  //......
}
JedisSentinelPool覆蓋了getResource和returnResource方法,其中getResource新增了設定dataSource給jedis,然後判斷master;returnResource方法新增了jedis的resetState操作,return有異常的話會執行returnBrokenResource

小結

jedis主要有三個物件對commons-pool進行包裝,分別是JedisPoolConfig(繼承了GenericObjectPoolConfig),JedisFactory(實現了PooledObjectFactory<Jedis>介面)、Pool(提供了get和return方法,內部委託給GenericObjectPool)

JedisPoolConfig繼承了GenericObjectPoolConfig,在構造器裡頭設定了預設的引數,即testWhileIdle為true,minEvictableIdleTime為60s,timeBetweenEvictionRuns為30s,numTestsPerEvictionRun為-1

相關文章