JedisPool源码解析
Posted 低调的洋仔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JedisPool源码解析相关的知识,希望对你有一定的参考价值。
JedisPoolConfig的继承结构
这个BaseObjectPoolConfig中无非是一部分常量和私有的变量。
public abstract class BaseObjectPoolConfig implements Cloneable
public static final boolean DEFAULT_LIFO = true;
public static final boolean DEFAULT_FAIRNESS = false;
public static final long DEFAULT_MAX_WAIT_MILLIS = -1L;
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1800000L;
public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1L;
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
public static final boolean DEFAULT_TEST_ON_CREATE = false;
public static final boolean DEFAULT_TEST_ON_BORROW = false;
public static final boolean DEFAULT_TEST_ON_RETURN = false;
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;
public static final boolean DEFAULT_JMX_ENABLE = true;
public static final String DEFAULT_JMX_NAME_PREFIX = "pool";
public static final String DEFAULT_JMX_NAME_BASE = null;
public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = "org.apache.commons.pool2.impl.DefaultEvictionPolicy";
private boolean lifo = true;
private boolean fairness = false;
private long maxWaitMillis = -1L;
private long minEvictableIdleTimeMillis = 1800000L;
private long softMinEvictableIdleTimeMillis = 1800000L;
private int numTestsPerEvictionRun = 3;
private String evictionPolicyClassName = "org.apache.commons.pool2.impl.DefaultEvictionPolicy";
private boolean testOnCreate = false;
private boolean testOnBorrow = false;
private boolean testOnReturn = false;
private boolean testWhileIdle = false;
private long timeBetweenEvictionRunsMillis = -1L;
private boolean blockWhenExhausted = true;
private boolean jmxEnabled = true;
private String jmxNamePrefix = "pool";
private String jmxNameBase = "pool";
然后它的子类补充了部分的常量和变量。
public class GenericObjectPoolConfig extends BaseObjectPoolConfig
public static final int DEFAULT_MAX_TOTAL = 8;
public static final int DEFAULT_MAX_IDLE = 8;
public static final int DEFAULT_MIN_IDLE = 0;
private int maxTotal = 8;
private int maxIdle = 8;
private int minIdle = 0;
然后实际初始化的是其构造方法。都是写死的。
public JedisPoolConfig()
this.setTestWhileIdle(true);
this.setMinEvictableIdleTimeMillis(60000L);
this.setTimeBetweenEvictionRunsMillis(30000L);
this.setNumTestsPerEvictionRun(-1);
例子
JedisPoolConfig config = new JedisPoolConfig();
config.setTestOnBorrow(true);
pool = new JedisPool(config, "", 2181, 2000, "foobared");
jedis = pool.getResource();
jedis.set("foo", "bar");
jedis.close();
Config部分创建了一个配置项实例。
设置部分参数可以。
然后这个地方创建了一个JedisPool的实例,这个实例,
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database)
this(poolConfig, host, port, timeout, password, database, (String)null);
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database, String clientName)
super(poolConfig, new JedisFactory(host, port, timeout, password, database, clientName));
JedisPool调用了父类的方法、
集成体系,JedisPool继承自Pool这个类,
public Pool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory)
this.initPool(poolConfig, factory);
public void initPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory)
if (this.internalPool != null)
try
this.closeInternalPool();
catch (Exception var4)
;
this.internalPool = new GenericObjectPool(factory, poolConfig);
调用Pool中的初始化pool方法。
这个方法中是调用了
GenericObjectPool
/** * Create a new <code>GenericObjectPool</code> using a specific * configuration. */ public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config) super(config, ONAME_BASE, config.getJmxNamePrefix()); if (factory == null) jmxUnregister(); // tidy up throw new IllegalArgumentException("factory may not be null"); this.factory = factory; idleObjects = new LinkedBlockingDeque<PooledObject<T>>(config.getFairness()); setConfig(config); startEvictor(getTimeBetweenEvictionRunsMillis());// 延迟一定的时间后设置逐出者。
初始化的GenericObjectPool
注意这里的重点是使用了LinkedBlockingDeque了,也就是双向链表实现的双端队列。空闲的连接放在这里面。
JedisPool中的方法。
getResource部分
获取空闲的连接、
public Jedis getResource() Jedis jedis = (Jedis)super.getResource(); jedis.setDataSource(this); return jedis;
调用了Pool中的方法。
public T getResource()
try
return this.internalPool.borrowObject();
catch (Exception var2)
throw new JedisConnectionException("Could not get a resource from the pool", var2);
调用GenericObjectPool中的方法
@Override public T borrowObject() throws Exception return borrowObject(getMaxWaitMillis());
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<T> p = null;
// Get local copy of current config so it is consistent for entire
// method execution
boolean blockWhenExhausted = getBlockWhenExhausted();
boolean create;
long waitTime = System.currentTimeMillis();
while (p == null)
create = false;
if (blockWhenExhausted)
p = idleObjects.pollFirst();
if (p == null)
p = create();
if (p != null)
create = true;
if (p == null)
if (borrowMaxWaitMillis < 0)
p = idleObjects.takeFirst();
else
p = idleObjects.pollFirst(borrowMaxWaitMillis,
TimeUnit.MILLISECONDS);
if (p == null)
throw new NoSuchElementException(
"Timeout waiting for idle object");
if (!p.allocate())
p = null;
else
p = 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)
try
factory.activateObject(p);
catch (Exception e)
try
destroy(p);
catch (Exception e1)
// Ignore - activation failure is more important
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 = 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;
updateStatsBorrow(p, System.currentTimeMillis() - waitTime);// 这里还带了延时的功能
return p.getObject();
pollFirst(borrowMaxWaitMillis,
TimeUnit.MILLISECONDS);
if (p == null)
throw new NoSuchElementException(
"Timeout waiting for idle object");
if (!p.allocate())
p = null;
else
p = 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)
try
factory.activateObject(p);
catch (Exception e)
try
destroy(p);
catch (Exception e1)
// Ignore - activation failure is more important
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 = 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;
updateStatsBorrow(p, System.currentTimeMillis() - waitTime);// 这里还带了延时的功能
return p.getObject();
然后剩下的就是jedis本身的操作了。
最后理清思路,首先是创建一个JedisPool的实例,这个实例会调用父类Pool中的方法来创建Pool,然后这个Pool中有一个internalPool,使得其等于一个GenericJedisPool,然后这个pool实际上空闲的会存储在LinkedBlockingDeque中去,然后在getResource的时候,会调jedisPool的方法然后调用父类的方法然后调用GenericPool的方法,然后就可以直接获取到空闲线程了。
@Override public E pollFirst() lock.lock(); try return unlinkFirst(); finally lock.unlock();
private E unlinkFirst()
// assert lock.isHeldByCurrentThread();
Node<E> f = first;
if (f == null)
return null;
Node<E> n = f.next;
E item = f.item;
f.item = null;
f.next = f; // help GC
first = n;
if (n == null)
last = null;
else
n.prev = null;
--count;
notFull.signal();
return item;
直接用的condition类的方法来实现的。
以上是关于JedisPool源码解析的主要内容,如果未能解决你的问题,请参考以下文章