jedis的return行為源碼解析
序
本文主要研究一下jedis的return行為
spring-data-redis
RedisTemplate
org/springframework/data/redis/core/RedisTemplate.java
@Nullable
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(action, "Callback object must not be null");
RedisConnectionFactory factory = getRequiredConnectionFactory();
RedisConnection conn = RedisConnectionUtils.getConnection(factory, enableTransactionSupport);
try {
boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
RedisConnection connToUse = preProcessConnection(conn, existingConnection);
boolean pipelineStatus = connToUse.isPipelined();
if (pipeline && !pipelineStatus) {
connToUse.openPipeline();
}
RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
T result = action.doInRedis(connToExpose);
// close pipeline
if (pipeline && !pipelineStatus) {
connToUse.closePipeline();
}
return postProcessResult(result, connToUse, existingConnection);
} finally {
RedisConnectionUtils.releaseConnection(conn, factory, enableTransactionSupport);
}
}RedisTemplate的execute方法先通過RedisConnectionUtils.getConnection獲取連接,最后通過RedisConnectionUtils.releaseConnection來歸還連接
RedisConnectionUtils
org/springframework/data/redis/core/RedisConnectionUtils.java
public static void releaseConnection(@Nullable RedisConnection conn, RedisConnectionFactory factory,
boolean transactionSupport) {
releaseConnection(conn, factory);
}
public static void releaseConnection(@Nullable RedisConnection conn, RedisConnectionFactory factory) {
if (conn == null) {
return;
}
RedisConnectionHolder conHolder = (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);
if (conHolder != null) {
if (conHolder.isTransactionActive()) {
if (connectionEquals(conHolder, conn)) {
if (log.isDebugEnabled()) {
log.debug("RedisConnection will be closed when transaction finished.");
}
// It's the transactional Connection: Don't close it.
conHolder.released();
}
return;
}
// release transactional/read-only and non-transactional/non-bound connections.
// transactional connections for read-only transactions get no synchronizer registered
unbindConnection(factory);
return;
}
doCloseConnection(conn);
}
private static void doCloseConnection(@Nullable RedisConnection connection) {
if (connection == null) {
return;
}
if (log.isDebugEnabled()) {
log.debug("Closing Redis Connection.");
}
try {
connection.close();
} catch (DataAccessException ex) {
log.debug("Could not close Redis Connection", ex);
} catch (Throwable ex) {
log.debug("Unexpected exception on closing Redis Connection", ex);
}
}releaseConnection方法主要是處理了事務(wù)相關(guān)的操作,最后執(zhí)行doCloseConnection,它最后執(zhí)行的是connection.close()
connection.close()
org/springframework/data/redis/connection/jedis/JedisConnection.java
@Override
public void close() throws DataAccessException {
super.close();
JedisSubscription subscription = this.subscription;
try {
if (subscription != null) {
subscription.close();
}
} catch (Exception ex) {
LOGGER.debug("Cannot terminate subscription", ex);
} finally {
this.subscription = null;
}
// return the connection to the pool
if (pool != null) {
jedis.close();
return;
}
// else close the connection normally (doing the try/catch dance)
try {
jedis.quit();
} catch (Exception ex) {
LOGGER.debug("Failed to QUIT during close", ex);
}
try {
jedis.disconnect();
} catch (Exception ex) {
LOGGER.debug("Failed to disconnect during close", ex);
}
}connection的close方法針對(duì)使用連接池的會(huì)執(zhí)行jedis.close,否則執(zhí)行jedis.quit
jedis.close()
redis/clients/jedis/Jedis.java
@Override
public void close() {
if (dataSource != null) {
JedisPoolAbstract pool = this.dataSource;
this.dataSource = null;
if (isBroken()) {
pool.returnBrokenResource(this);
} else {
pool.returnResource(this);
}
} else {
super.close();
}
}jedis的close方法會(huì)先判斷isBroken(取的redis.clients.jedis.Connection.broken屬性),如果是則執(zhí)行returnBrokenResource,否則執(zhí)行returnResource
pool
redis/clients/jedis/util/Pool.java
public void returnBrokenResource(final T resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
public void returnResource(final T resource) {
if (resource != null) {
returnResourceObject(resource);
}
}
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);
}
}
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);
}
}returnBrokenResource執(zhí)行的是internalPool.invalidateObject(resource),而returnResourceObject執(zhí)行的是internalPool.returnObject(resource)
invalidateObject
org/apache/commons/pool2/impl/GenericObjectPool.java
public void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception {
final PooledObject<T> p = getPooledObject(obj);
if (p == null) {
if (isAbandonedConfig()) {
return;
}
throw new IllegalStateException(
"Invalidated object not currently part of this pool");
}
synchronized (p) {
if (p.getState() != PooledObjectState.INVALID) {
destroy(p, destroyMode);
}
}
ensureIdle(1, false);
}
private void destroy(final PooledObject<T> toDestroy, final DestroyMode destroyMode) throws Exception {
toDestroy.invalidate();
idleObjects.remove(toDestroy);
allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
try {
factory.destroyObject(toDestroy, destroyMode);
} finally {
destroyedCount.incrementAndGet();
createCount.decrementAndGet();
}
}invalidateObject方法執(zhí)行的是destroy方法,該方法會(huì)回調(diào)factory.destroyObject
destroyObject
redis/clients/jedis/JedisFactory.java
public void destroyObject(PooledObject<Jedis> pooledJedis) throws Exception {
final BinaryJedis jedis = pooledJedis.getObject();
if (jedis.isConnected()) {
try {
// need a proper test, probably with mock
if (!jedis.isBroken()) {
jedis.quit();
}
} catch (RuntimeException e) {
logger.warn("Error while QUIT", e);
}
try {
jedis.close();
} catch (RuntimeException e) {
logger.warn("Error while close", e);
}
}
}destroyObject方法則執(zhí)行jedis.close()關(guān)閉client連接
returnObject
org/apache/commons/pool2/impl/GenericObjectPool.java
public void returnObject(final T obj) {
final PooledObject<T> p = getPooledObject(obj);
if (p == null) {
if (!isAbandonedConfig()) {
throw new IllegalStateException(
"Returned object not currently part of this pool");
}
return; // Object was abandoned and removed
}
markReturningState(p);
final Duration activeTime = p.getActiveDuration();
if (getTestOnReturn() && !factory.validateObject(p)) {
try {
destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
try {
ensureIdle(1, false);
} catch (final Exception e) {
swallowException(e);
}
updateStatsReturn(activeTime);
return;
}
try {
factory.passivateObject(p);
} catch (final Exception e1) {
swallowException(e1);
try {
destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
try {
ensureIdle(1, false);
} catch (final Exception e) {
swallowException(e);
}
updateStatsReturn(activeTime);
return;
}
if (!p.deallocate()) {
throw new IllegalStateException(
"Object has already been returned to this pool or is invalid");
}
final int maxIdleSave = getMaxIdle();
if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
try {
destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
try {
ensureIdle(1, false);
} catch (final Exception e) {
swallowException(e);
}
} else {
if (getLifo()) {
idleObjects.addFirst(p);
} else {
idleObjects.addLast(p);
}
if (isClosed()) {
// Pool closed while object was being added to idle objects.
// Make sure the returned object is destroyed rather than left
// in the idle object pool (which would effectively be a leak)
clear();
}
}
updateStatsReturn(activeTime);
}returnObject針對(duì)testOnReturn的會(huì)執(zhí)行validateObject方法,之后執(zhí)行factory.passivateObject(p),最后根據(jù)maxIdle的參數(shù)來判斷,超出的則執(zhí)行destroy,否則根據(jù)是否Lifo放回到連接池(idleObjects)中
小結(jié)
spring-data-redis的return主要是執(zhí)行connection的close方法,對(duì)應(yīng)到j(luò)edis就是jedis.close(),它會(huì)先判斷isBroken(取的redis.clients.jedis.Connection.broken屬性),如果是則執(zhí)行returnBrokenResource,否則執(zhí)行returnResource。
- returnBrokenResource執(zhí)行的是internalPool.invalidateObject(resource),invalidateObject方法執(zhí)行的是destroy方法,該方法會(huì)回調(diào)factory.destroyObject方法,即執(zhí)行jedis.close()關(guān)閉client連接
- returnObject針對(duì)testOnReturn的會(huì)執(zhí)行validateObject方法,之后執(zhí)行factory.passivateObject(p),最后根據(jù)maxIdle的參數(shù)來判斷,超出的則執(zhí)行destroy,否則根據(jù)是否Lifo放回到連接池(
idleObjects)中 - 也就說假設(shè)獲取連接之后,執(zhí)行的時(shí)候redis掛了,redis.clients.jedis.Connection會(huì)標(biāo)記broken為true,同時(shí)拋出JedisConnectionException;而RedisTemplate是在finally中進(jìn)行releaseConnection,因而歸還的時(shí)候會(huì)觸發(fā)returnBrokenResource從而關(guān)閉壞掉的連接,間接實(shí)現(xiàn)
testOnReturn的效果 - 如果在獲取連接的時(shí)候,redis掛了,但是連接池仍然有連接,若沒有testOnBorrow則返回然后使用,但是使用的時(shí)候會(huì)報(bào)錯(cuò),即redis.clients.jedis.Connection會(huì)標(biāo)記broken為true,同時(shí)拋出JedisConnectionException,歸還的時(shí)候直接銷毀;若有testOnBorrow則validate的時(shí)候能驗(yàn)證出來連接有問題,則會(huì)執(zhí)行destory然后繼續(xù)循環(huán)獲取連接池的連接,直到連接池連接沒有了;若獲取連接的時(shí)候連接池沒有空閑連接了,則走create的邏輯,這個(gè)時(shí)候create直接拋出redis.clients.jedis.exceptions.JedisConnectionException: Failed to create socket.
以上就是jedis的return行為源碼解析的詳細(xì)內(nèi)容,更多關(guān)于jedis return行為的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java利用遞歸算法實(shí)現(xiàn)對(duì)文件夾的刪除功能
這篇文章主要介紹了java利用遞歸算法實(shí)現(xiàn)對(duì)文件夾的刪除功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼
這篇文章主要介紹了java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼的相關(guān)資料,將秒或分鐘的值轉(zhuǎn)換為xx天xx小時(shí)xx分鐘xx秒 如果 “xx” 為0 自動(dòng)缺省,需要的朋友可以參考下2017-07-07
淺析SpringBoot自動(dòng)化配置原理實(shí)現(xiàn)
這篇文章主要介紹了淺析SpringBoot自動(dòng)化配置原理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
selenium高效應(yīng)對(duì)Web頁面元素刷新的實(shí)例講解
今天小編就為大家分享一篇selenium高效應(yīng)對(duì)Web頁面元素刷新的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-05-05

