概述
Jedis的設置項中有一個testOnBorrow的配置項,這個配置項其實來自於Apache CommonPools,意思是從連接池中取出是檢查連接是否失活。
最近需要把項目中的Redis客戶端從Jedis切換成Lettuce,發現Lettuce中沒有testOnBorrow的這個配置項,倒是有一個pingBeforeActivateConnection配置項(官方說法是在使用連接前,先進行PING檢查連接),本着遷移時不對項目現有配置做改動的原則,研究下Jedis的testOnBorrow配置項的底層實現。
步驟
藉助IDEA來進行源碼探索,maven下載包的同時要下載源碼文件
- 設置是利用JedisPoolConfig的setTestOnBorrow(boolean)來設置的。於是跳轉到this.testOnBorrow變量。
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
- 對testOnBorrow變量利用Alt+F7快捷鍵反查所有用到的地方,查看變量被讀取的地方,可以發現org.apache.commons.pool2.impl.BaseGenericObjectPool.setConfig這裏獲取了變量並利用setTestOnBorrow設置進自身的testOnBorrow變量。
- 反查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;
}
}
}
- 可以發現
validate = factory.validateObject(p);
這個是關鍵點,在這裏,池化對象p被校驗。 - 查看
validateObject()
的實現,可以發現有多個實現,我們選擇Jedis的實現(即:redis.clients.jedis.JedisFactory.validateObject) - 答案在此揭曉:
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配置項。