Jedis是Redis的Java客户端,连接池使用commons-pool2。此文记录Jedis的设计,也探讨连接池的实现。
版本:jedis-3.1.0-m1
Jedis对象
Jedis对象的继承关系:Jedis
—>BinaryJedis
- - - ->BasicCommands
、BinaryJedisCommands
等,其中BinaryJedis
组合了Client对象(Client
—>BinaryClient
—>Connection
,Connection对象组合了socket、输入输出流等连接对象)
JedisPool初始化
JedisPool的构造方法很多(可以改造成Builder Pattern,更清晰),可以通过JedisConfig进行配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxActive(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWait(MAX_WAIT);
config.setMaxWait(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
JedisPool的继承关系:JedisPool
—>JedisPoolAbstract
—>Pool
JedisPool的构造,依赖于抽象父类Pool
的构造函数,如下:
//Pool中内置的属性是commons-pool2的GenericObjectPool
private final GenericObjectPool internalPool;
public Pool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {
initPool(poolConfig, factory);
}
public void initPool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {
//...
this.internalPool = new GenericObjectPool<T>(factory, poolConfig);
}
Pool中内置的属性是commons-pool2的GenericObjectPool
,即最终的连接池对象:
public GenericObjectPool(final PooledObjectFactory<T> factory,
final GenericObjectPoolConfig config) {
//...
this.factory = factory;
idleObjects = new LinkedBlockingDeque<>(config.getFairness());
//...
}
其中构造参数final PooledObjectFactory<T> factory
,是外层构造时传入的JedisFactory
,其实现了接口PoolObjectFactory
,并实现了makeObject()
等相关方法,即产生Jedis类的真正工厂。
Jedis连接获取
上文提到的makeObject()
真正被调用的时候,是在连接获取时,进行调用并创建Jedis对象 (当然是有条件的,即下文提到的存活队列中无可用对象,并未达到上限时)
private PooledObject<T> create() throws Exception {
//判断连接池容量的逻辑...
final PooledObject<T> p;
try {
p = factory.makeObject();
} catch (final Exception e) {
createCount.decrementAndGet();
throw e;
}finally {
synchronized (makeObjectCountLock) {
makeObjectCount--;
//此处唤醒所有等待连接的线程
makeObjectCountLock.notifyAll();
}
}
}
Jedis连接关闭
这里必须要提到,在连接池对象中(GenericObjectPool
)的一个重要属性:
private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
这个阻塞队列是维护存活Jedis对象的容器,当连接关闭时,Jedis对象归还连接池,即存入此队列,保持连接的存活。
final int maxIdleSave = getMaxIdle();
if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
try {
destroy(p);
} catch (final Exception e) {
swallowException(e);
}
} else {
if (getLifo()) {
idleObjects.addFirst(p);
} else {
idleObjects.addLast(p);
}
}
总结
此文只是对Jedis源码的粗略解读,主要想了解连接池的设计,以及通过线程安全的变量、锁等机制,控制连接池的状态。
还有诸多细节,待后续补充。
网友评论