问题
spring-data-redis类加载阻塞问题。
分析
org.springframework.data.redis.core.RedisTemplate#execute(org.springframework.data.redis.core.RedisCallback<T>, boolean, boolean)
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
// 省略
// 是否暴露connection,connToExpose=false会新建代理类
RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
T result = action.doInRedis(connToExpose);
if (pipeline && !pipelineStatus) {
connToUse.closePipeline();
}
return postProcessResult(result, connToUse, existingConnection);
} finally {
}
}
connection代理类
protected RedisConnection createRedisConnectionProxy(RedisConnection pm) {
// 会触发类加载
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(pm.getClass(), getClass().getClassLoader());
return (RedisConnection) Proxy.newProxyInstance(pm.getClass().getClassLoader(), ifcs,
new CloseSuppressingInvocationHandler(pm));
}
禁止关闭连接代理类
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals(EQUALS)) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
} else if (method.getName().equals(HASH_CODE)) {
// Use hashCode of PersistenceManager proxy.
return System.identityHashCode(proxy);
// 代理close方法,什么都不做
} else if (method.getName().equals(CLOSE)) {
// Handle close method: suppress, not valid.
return null;
}
try {
Object retVal = method.invoke(this.target, args);
return retVal;
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
结论
exposeConnection作用:是否暴露connection。如果暴露,connection会暴露在回调函数里
org.springframework.data.redis.core.DefaultValueOperations#increment(K, long)
public Long increment(K key, final long delta) {
final byte[] rawKey = rawKey(key);
return execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) {
// 这里可以把connection关闭,不安全。
return connection.incrBy(rawKey, delta);
}
// 一般会设置为true
}, true);
}
RedisTemplate的exposeConnection默认为false,在操作的时候一般需要显示传参设置为true。
网友评论