jedis 源码阅读二——jedisPool

我们从这段代码分析jedisPool:

JedisPool

  @Test
  public void checkJedisIsReusedWhenReturned() {

    JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort());
    Jedis jedis = pool.getResource();
    jedis.auth("foobared");
    jedis.set("foo", "0");
    jedis.close();

    jedis = pool.getResource();
    jedis.auth("foobared");
    jedis.incr("foo");
    jedis.close();
    pool.destroy();
    assertTrue(pool.isClosed());
  }

接着我们看这个Pool,是什么?怎么实现的?

JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort());

public class JedisPool extends JedisPoolAbstract {

 .......
		public JedisPool(final String host) {
		URI uri = URI.create(host);
		if (JedisURIHelper.isValid(uri)) {
			String h = uri.getHost();
			int port = uri.getPort();
			String password = JedisURIHelper.getPassword(uri);
			int database = JedisURIHelper.getDBIndex(uri);
			
			// 这里创建了一个Pool,jedisPool使用org.apache.commons.pool2.impl.GenericObjectPool.GenericObjectPool<Jedis>实现
			// 在父类Pool里声明一个protected GenericObjectPool<T>internalPool对象;(JedisPool extends JedisPoolAbstract extends Pool)
			//GenericObjectPool(...)有两个参数,第二个是默认的池配置。稍后看一下第一个参数 JedisFactory
			
			this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(h, port, Protocol.DEFAULT_TIMEOUT,
					Protocol.DEFAULT_TIMEOUT, password, database, null), new GenericObjectPoolConfig());
		} else {
			this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host, Protocol.DEFAULT_PORT,
					Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE, null),
					new GenericObjectPoolConfig());
		}
	}
	
 .......

	@Override
	public Jedis getResource() {
		//从池中获取jedis,父类又是如何获取的?稍后看一下它的父类Pool.java
		Jedis jedis = super.getResource();
		jedis.setDataSource(this);
		return jedis;
	}

JedisFactory.java

首先它继承自PooledObjectFactory:

package org.apache.commons.pool2;
public abstract interface PooledObjectFactory<T> {
	// 创建池中对象
	public abstract PooledObject<T> makeObject() throws Exception;

	// 销毁池中对象
	public abstract void destroyObject(PooledObject<T> paramPooledObject) throws Exception;

	// 验证池中对象
	public abstract boolean validateObject(PooledObject<T> paramPooledObject);

	// 获取池中对象
	public abstract void activateObject(PooledObject<T> paramPooledObject) throws Exception;

	// 钝化池对象,未实现
	public abstract void passivateObject(PooledObject<T> paramPooledObject) throws Exception;
}

我们来看JedisFactory的实现:

  @Override
  public PooledObject<Jedis> makeObject() throws Exception {
    final HostAndPort hostAndPort = this.hostAndPort.get();
    final Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), connectionTimeout,
        soTimeout);

    try {
      jedis.connect();
      if (null != this.password) {
        jedis.auth(this.password);
      }
      if (database != 0) {
        jedis.select(database);
      }
      if (clientName != null) {
        jedis.clientSetname(clientName);
      }
    } catch (JedisException je) {
      jedis.close();
      throw je;
    }

    return new DefaultPooledObject<Jedis>(jedis);

  }
  @Override
  public void destroyObject(PooledObject<Jedis> pooledJedis) throws Exception {
    final BinaryJedis jedis = pooledJedis.getObject();
    if (jedis.isConnected()) {
      try {
        try {
          jedis.quit();
        } catch (Exception e) {
        }
        jedis.disconnect();
      } catch (Exception e) {

      }
    }

  }
  @Override
  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;
    }
  }
}
  @Override
  public void activateObject(PooledObject<Jedis> pooledJedis) throws Exception {
  //return 
    final BinaryJedis jedis = pooledJedis.getObject();
    if (jedis.getDB() != database) {
      jedis.select(database);
    }

  }
  @Override
  public void passivateObject(PooledObject<Jedis> pooledJedis) throws Exception {
    // TODO maybe should select db 0? Not sure right now.
  }

以上代码很清晰,不做解释。
好,池对象ok,我们看看jedisPool的父类Pool.java如何获取Jedis:


  public T getResource() {
    try {
    //  protected GenericObjectPool<T> internalPool;
      return internalPool.borrowObject();
    } catch (Exception e) {
      throw new JedisConnectionException("Could not get a resource from the pool", e);
    }
  }

是通过调用GenericObjectPool.borrowObject():

GenericObjectPool.java


public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
		implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
	private volatile String factoryType;
	private volatile int maxIdle;
	private volatile int minIdle;
	private final PooledObjectFactory<T> factory;
	private final Map<T, PooledObject<T>> allObjects;// 存放所有的Jedis包装类对象(DefaultPooledObject)
	private final AtomicLong createCount;
	private final LinkedBlockingDeque<PooledObject<T>> idleObjects;// 存放idle的Jedis包装类对象(DefaultPooledObject)
	private static final String ONAME_BASE = "org.apache.commons.pool2:type=GenericObjectPool,name=";
	private volatile AbandonedConfig abandonedConfig;

........

	public T borrowObject(long borrowMaxWaitMillis) throws Exception {
		assertOpen();

		AbandonedConfig ac = this.abandonedConfig;
		if ((ac != null) && (ac.getRemoveAbandonedOnBorrow()) && (getNumIdle() < 2)
				&& (getNumActive() > getMaxTotal() - 3)) {
			removeAbandoned(ac);
		}

		PooledObject p = null;

		boolean blockWhenExhausted = getBlockWhenExhausted();

		long waitTime = System.currentTimeMillis();

		while (p == null) {
			boolean create = false;
			if (blockWhenExhausted) {
				// 轮询获取池中对象,也就是PooledObject;PooledObject可以理解为jedis的包装对象
				p = (PooledObject) this.idleObjects.pollFirst();
				if (p == null) {
					// 如果没有就创建并返回这个PooledObject对象
					p = create();
					if (p != null) {
						create = true;
					}
				}
				if (p == null) {
					if (borrowMaxWaitMillis < 0L)
						p = (PooledObject) this.idleObjects.takeFirst();
					else {
						p = (PooledObject) this.idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
					}
				}

				if (p == null) {
					throw new NoSuchElementException("Timeout waiting for idle object");
				}

				if (!(p.allocate()))
					p = null;
			} else {
				p = (PooledObject) this.idleObjects.pollFirst();
				if (p == null) {
					p = create();
					if (p != null) {
						create = true;
					}
				}
				if (p == null) {
					throw new NoSuchElementException("Pool exhausted");
				}
				if (!(p.allocate())) {
					p = null;
				}
			}

			if (p == null)
				continue;
			try {
				this.factory.activateObject(p);
			} catch (Exception e) {
				try {
					destroy(p);
				} catch (Exception e1) {
				}
				p = null;
				if (create) {
					NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");

					nsee.initCause(e);
					throw nsee;
				}
			}
			if ((p != null) && (((getTestOnBorrow()) || ((create) && (getTestOnCreate())))))
				;
			boolean validate = false;
			Throwable validationThrowable = null;
			try {
				// 验证有效
				validate = this.factory.validateObject(p);
			} catch (Throwable t) {
				PoolUtils.checkRethrow(t);
				validationThrowable = t;
			}
			if (!(validate)) {
				try {
					destroy(p);
					this.destroyedByBorrowValidationCount.incrementAndGet();
				} catch (Exception e) {
				}
				p = null;
				if (create) {
					NoSuchElementException nsee = new NoSuchElementException("Unable to validate object");

					nsee.initCause(validationThrowable);
					throw nsee;
				}

			}

		}

		updateStatsBorrow(p, System.currentTimeMillis() - waitTime);

		// 最终返回这个jedis,当使用完调用closes时放入LinkedBlockingDeque<PooledObject<T>>
		// idleObjects中
		return p.getObject();
	}

一个UnitTest加深理解:

	@Test
	public void checkJedisIsReusedWhenReturned() {

		JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort());
		Jedis jedis = pool.getResource();// 产生一个Jedis包装类,并getObject()返回Jedis.
		// jedis.auth("foobared");
		Jedis jedis2 = pool.getResource();
		jedis.set("foo", "0");
		jedis.set("foo2", "0");

		System.out.println(jedis);// redis.clients.jedis.Jedis@19e3cd51

		System.out.println(jedis2);// redis.clients.jedis.Jedis@3abc8e1e
		// 现在池中有两个jedis对象

		jedis.close();

		jedis = pool.getResource();
		System.out.println(jedis);// redis.clients.jedis.Jedis@19e3cd51;返回其中一个并使用

		// jedis.auth("foobared");
		jedis.incr("foo");
		jedis.close();
		pool.destroy();
		assertTrue(pool.isClosed());
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值