博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JedisConnectionFactory 和 JedisPool
阅读量:5756 次
发布时间:2019-06-18

本文共 18463 字,大约阅读时间需要 61 分钟。

hot3.png

这就是 JedisConnectionFactory 源码。

/* * Copyright 2011-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.data.redis.connection.jedis;import java.lang.reflect.Method;import java.util.Collection;import java.util.Collections;import java.util.LinkedHashSet;import java.util.Set;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;import org.springframework.dao.DataAccessException;import org.springframework.dao.InvalidDataAccessResourceUsageException;import org.springframework.data.redis.ExceptionTranslationStrategy;import org.springframework.data.redis.PassThroughExceptionTranslationStrategy;import org.springframework.data.redis.RedisConnectionFailureException;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.connection.RedisNode;import org.springframework.data.redis.connection.RedisSentinelConfiguration;import org.springframework.data.redis.connection.RedisSentinelConnection;import org.springframework.util.Assert;import org.springframework.util.CollectionUtils;import org.springframework.util.ReflectionUtils;import org.springframework.util.StringUtils;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;import redis.clients.jedis.JedisSentinelPool;import redis.clients.jedis.JedisShardInfo;import redis.clients.jedis.Protocol;import redis.clients.util.Pool;/** * Connection factory creating Jedis based connections. *  * @author Costin Leau * @author Thomas Darimont * @author Christoph Strobl */public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {	private final static Log log = LogFactory.getLog(JedisConnectionFactory.class);	private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy(			JedisConverters.exceptionConverter());	private static final Method SET_TIMEOUT_METHOD;	private static final Method GET_TIMEOUT_METHOD;	static {		// We need to configure Jedis socket timeout via reflection since the method-name was changed between releases.		Method setTimeoutMethodCandidate = ReflectionUtils.findMethod(JedisShardInfo.class, "setTimeout", int.class);		if (setTimeoutMethodCandidate == null) {			// Jedis V 2.7.x changed the setTimeout method to setSoTimeout			setTimeoutMethodCandidate = ReflectionUtils.findMethod(JedisShardInfo.class, "setSoTimeout", int.class);		}		SET_TIMEOUT_METHOD = setTimeoutMethodCandidate;		Method getTimeoutMethodCandidate = ReflectionUtils.findMethod(JedisShardInfo.class, "getTimeout");		if (getTimeoutMethodCandidate == null) {			getTimeoutMethodCandidate = ReflectionUtils.findMethod(JedisShardInfo.class, "getSoTimeout");		}		GET_TIMEOUT_METHOD = getTimeoutMethodCandidate;	}	private JedisShardInfo shardInfo;	private String hostName = "localhost";	private int port = Protocol.DEFAULT_PORT;	private int timeout = Protocol.DEFAULT_TIMEOUT;	private String password;	private boolean usePool = true;	private Pool
pool; private JedisPoolConfig poolConfig = new JedisPoolConfig(); private int dbIndex = 0; private boolean convertPipelineAndTxResults = true; private RedisSentinelConfiguration sentinelConfig; /** * Constructs a new
JedisConnectionFactory instance with default settings (default connection pooling, no * shard information). */ public JedisConnectionFactory() {} /** * Constructs a new
JedisConnectionFactory instance. Will override the other connection parameters passed * to the factory. * * @param shardInfo shard information */ public JedisConnectionFactory(JedisShardInfo shardInfo) { this.shardInfo = shardInfo; } /** * Constructs a new
JedisConnectionFactory instance using the given pool configuration. * * @param poolConfig pool configuration */ public JedisConnectionFactory(JedisPoolConfig poolConfig) { this(null, poolConfig); } /** * Constructs a new {@link JedisConnectionFactory} instance using the given {@link JedisPoolConfig} applied to * {@link JedisSentinelPool}. * * @param sentinelConfig * @since 1.4 */ public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfig) { this(sentinelConfig, null); } /** * Constructs a new {@link JedisConnectionFactory} instance using the given {@link JedisPoolConfig} applied to * {@link JedisSentinelPool}. * * @param sentinelConfig * @param poolConfig pool configuration. Defaulted to new instance if {@literal null}. * @since 1.4 */ public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfig, JedisPoolConfig poolConfig) { this.sentinelConfig = sentinelConfig; this.poolConfig = poolConfig != null ? poolConfig : new JedisPoolConfig(); } /** * Returns a Jedis instance to be used as a Redis connection. The instance can be newly created or retrieved from a * pool. * * @return Jedis instance ready for wrapping into a {@link RedisConnection}. */ protected Jedis fetchJedisConnector() { try { if (usePool && pool != null) { return pool.getResource(); } Jedis jedis = new Jedis(getShardInfo()); // force initialization (see Jedis issue #82) jedis.connect(); return jedis; } catch (Exception ex) { throw new RedisConnectionFailureException("Cannot get Jedis connection", ex); } } /** * Post process a newly retrieved connection. Useful for decorating or executing initialization commands on a new * connection. This implementation simply returns the connection. * * @param connection * @return processed connection */ protected JedisConnection postProcessConnection(JedisConnection connection) { return connection; } /* * (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() { if (shardInfo == null) { shardInfo = new JedisShardInfo(hostName, port); if (StringUtils.hasLength(password)) { shardInfo.setPassword(password); } if (timeout > 0) { setTimeoutOn(shardInfo, timeout); } } if (usePool) { this.pool = createPool(); } } private Pool
createPool() { if (isRedisSentinelAware()) { return createRedisSentinelPool(this.sentinelConfig); } return createRedisPool(); } /** * Creates {@link JedisSentinelPool}. * * @param config * @return * @since 1.4 */ protected Pool
createRedisSentinelPool(RedisSentinelConfiguration config) { return new JedisSentinelPool(config.getMaster().getName(), convertToJedisSentinelSet(config.getSentinels()), getPoolConfig() != null ? getPoolConfig() : new JedisPoolConfig(), getTimeoutFrom(getShardInfo()), getShardInfo().getPassword()); } /** * Creates {@link JedisPool}. * * @return * @since 1.4 */ protected Pool
createRedisPool() { return new JedisPool(getPoolConfig(), getShardInfo().getHost(), getShardInfo().getPort(), getTimeoutFrom(getShardInfo()), getShardInfo().getPassword()); } /* * (non-Javadoc) * @see org.springframework.beans.factory.DisposableBean#destroy() */ public void destroy() { if (usePool && pool != null) { try { pool.destroy(); } catch (Exception ex) { log.warn("Cannot properly close Jedis pool", ex); } pool = null; } } /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisConnectionFactory#getConnection() */ public JedisConnection getConnection() { Jedis jedis = fetchJedisConnector(); JedisConnection connection = (usePool ? new JedisConnection(jedis, pool, dbIndex) : new JedisConnection(jedis, null, dbIndex)); connection.setConvertPipelineAndTxResults(convertPipelineAndTxResults); return postProcessConnection(connection); } /* * (non-Javadoc) * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException) */ public DataAccessException translateExceptionIfPossible(RuntimeException ex) { return EXCEPTION_TRANSLATION.translate(ex); } /** * Returns the Redis hostName. * * @return Returns the hostName */ public String getHostName() { return hostName; } /** * Sets the Redis hostName. * * @param hostName The hostName to set. */ public void setHostName(String hostName) { this.hostName = hostName; } /** * Returns the password used for authenticating with the Redis server. * * @return password for authentication */ public String getPassword() { return password; } /** * Sets the password used for authenticating with the Redis server. * * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * Returns the port used to connect to the Redis instance. * * @return Redis port. */ public int getPort() { return port; } /** * Sets the port used to connect to the Redis instance. * * @param port Redis port */ public void setPort(int port) { this.port = port; } /** * Returns the shardInfo. * * @return Returns the shardInfo */ public JedisShardInfo getShardInfo() { return shardInfo; } /** * Sets the shard info for this factory. * * @param shardInfo The shardInfo to set. */ public void setShardInfo(JedisShardInfo shardInfo) { this.shardInfo = shardInfo; } /** * Returns the timeout. * * @return Returns the timeout */ public int getTimeout() { return timeout; } /** * @param timeout The timeout to set. */ public void setTimeout(int timeout) { this.timeout = timeout; } /** * Indicates the use of a connection pool. * * @return Returns the use of connection pooling. */ public boolean getUsePool() { return usePool; } /** * Turns on or off the use of connection pooling. * * @param usePool The usePool to set. */ public void setUsePool(boolean usePool) { this.usePool = usePool; } /** * Returns the poolConfig. * * @return Returns the poolConfig */ public JedisPoolConfig getPoolConfig() { return poolConfig; } /** * Sets the pool configuration for this factory. * * @param poolConfig The poolConfig to set. */ public void setPoolConfig(JedisPoolConfig poolConfig) { this.poolConfig = poolConfig; } /** * Returns the index of the database. * * @return Returns the database index */ public int getDatabase() { return dbIndex; } /** * Sets the index of the database used by this connection factory. Default is 0. * * @param index database index */ public void setDatabase(int index) { Assert.isTrue(index >= 0, "invalid DB index (a positive index required)"); this.dbIndex = index; } /** * Specifies if pipelined results should be converted to the expected data type. If false, results of * {@link JedisConnection#closePipeline()} and {@link JedisConnection#exec()} will be of the type returned by the * Jedis driver * * @return Whether or not to convert pipeline and tx results */ public boolean getConvertPipelineAndTxResults() { return convertPipelineAndTxResults; } /** * Specifies if pipelined results should be converted to the expected data type. If false, results of * {@link JedisConnection#closePipeline()} and {@link JedisConnection#exec()} will be of the type returned by the * Jedis driver * * @param convertPipelineAndTxResults Whether or not to convert pipeline and tx results */ public void setConvertPipelineAndTxResults(boolean convertPipelineAndTxResults) { this.convertPipelineAndTxResults = convertPipelineAndTxResults; } /** * @return true when {@link RedisSentinelConfiguration} is present. * @since 1.4 */ public boolean isRedisSentinelAware() { return sentinelConfig != null; } /* (non-Javadoc) * @see org.springframework.data.redis.connection.RedisConnectionFactory#getSentinelConnection() */ @Override public RedisSentinelConnection getSentinelConnection() { if (!isRedisSentinelAware()) { throw new InvalidDataAccessResourceUsageException("No Sentinels configured"); } return new JedisSentinelConnection(getActiveSentinel()); } private Jedis getActiveSentinel() { Assert.notNull(this.sentinelConfig); for (RedisNode node : this.sentinelConfig.getSentinels()) { Jedis jedis = new Jedis(node.getHost(), node.getPort()); if (jedis.ping().equalsIgnoreCase("pong")) { return jedis; } } throw new InvalidDataAccessResourceUsageException("no sentinel found"); } private Set
convertToJedisSentinelSet(Collection
nodes) { if (CollectionUtils.isEmpty(nodes)) { return Collections.emptySet(); } Set
convertedNodes = new LinkedHashSet
(nodes.size()); for (RedisNode node : nodes) { if (node != null) { convertedNodes.add(node.asString()); } } return convertedNodes; } private void setTimeoutOn(JedisShardInfo shardInfo, int timeout) { ReflectionUtils.invokeMethod(SET_TIMEOUT_METHOD, shardInfo, timeout); } private int getTimeoutFrom(JedisShardInfo shardInfo) { return (Integer) ReflectionUtils.invokeMethod(GET_TIMEOUT_METHOD, shardInfo); }}

先看下Pool这个连接池对象。

package redis.clients.util;import java.io.Closeable;import org.apache.commons.pool2.PooledObjectFactory;import org.apache.commons.pool2.impl.GenericObjectPool;import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import redis.clients.jedis.exceptions.JedisConnectionException;import redis.clients.jedis.exceptions.JedisException;public abstract class Pool
implements Closeable { protected GenericObjectPool
internalPool; /** * Using this constructor means you have to set and initialize the internalPool yourself. */ public Pool() { } @Override public void close() { destroy(); } public boolean isClosed() { return this.internalPool.isClosed(); } public Pool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory
factory) { initPool(poolConfig, factory); } public void initPool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory
factory) { if (this.internalPool != null) { try { closeInternalPool(); } catch (Exception e) { } } this.internalPool = new GenericObjectPool
(factory, poolConfig); } public T getResource() { try { return internalPool.borrowObject(); } catch (Exception e) { throw new JedisConnectionException("Could not get a resource from the pool", e); } } /** * @deprecated starting from Jedis 3.0 this method won't exist. Resouce cleanup should be done * using @see {@link redis.clients.jedis.Jedis#close()} */ @Deprecated public void returnResourceObject(final T resource) { if (resource == null) { return; } try { internalPool.returnObject(resource); } catch (Exception e) { throw new JedisException("Could not return the resource to the pool", e); } } public void returnBrokenResource(final T resource) { if (resource != null) { returnBrokenResourceObject(resource); } } public void returnResource(final T resource) { if (resource != null) { returnResourceObject(resource); } } public void destroy() { closeInternalPool(); } protected void returnBrokenResourceObject(final T resource) { try { internalPool.invalidateObject(resource); } catch (Exception e) { throw new JedisException("Could not return the resource to the pool", e); } } protected void closeInternalPool() { try { internalPool.close(); } catch (Exception e) { throw new JedisException("Could not destroy the pool", e); } } public int getNumActive() { if (poolInactive()) { return -1; } return this.internalPool.getNumActive(); } public int getNumIdle() { if (poolInactive()) { return -1; } return this.internalPool.getNumIdle(); } public int getNumWaiters() { if (poolInactive()) { return -1; } return this.internalPool.getNumWaiters(); } public long getMeanBorrowWaitTimeMillis() { if (poolInactive()) { return -1; } return this.internalPool.getMeanBorrowWaitTimeMillis(); } public long getMaxBorrowWaitTimeMillis() { if (poolInactive()) { return -1; } return this.internalPool.getMaxBorrowWaitTimeMillis(); } private boolean poolInactive() { return this.internalPool == null || this.internalPool.isClosed(); } public void addObjects(int count) { try { for (int i = 0; i < count ; i++) { this.internalPool.addObject(); } } catch (Exception e) { throw new JedisException("Error trying to add idle objects", e); } }}

哎呀还有个接口:

package java.io;import java.io.IOException;/** * A {@code Closeable} is a source or destination of data that can be closed. * The close method is invoked to release resources that the object is * holding (such as open files). * * @since 1.5 */public interface Closeable extends AutoCloseable {    /**     * Closes this stream and releases any system resources associated     * with it. If the stream is already closed then invoking this     * method has no effect.     *     * 

As noted in {@link AutoCloseable#close()}, cases where the * close may fail require careful attention. It is strongly advised * to relinquish the underlying resources and to internally * mark the {@code Closeable} as closed, prior to throwing * the {@code IOException}. * * @throws IOException if an I/O error occurs */ public void close() throws IOException;}

Pool实现了自动关闭连接接口,pool又是怎样实现的呢?

@Override  public void close() {    destroy();  }  public void destroy() {    closeInternalPool();  }  protected void closeInternalPool() {    try {      internalPool.close();    } catch (Exception e) {      throw new JedisException("Could not destroy the pool", e);    }  }    protected GenericObjectPool
internalPool;

这里又有个他GenericObjectPool什么鬼接着扒一扒:

通过这会博客,明白了通用连接池对象的原理,

edis pool 和 spring 实现基本类似,都是用了GenericObjectPool进行管理i。

 

转载于:https://my.oschina.net/u/3418748/blog/1511027

你可能感兴趣的文章
坚信每个人都能成为品牌
查看>>
JAVA的对象复制
查看>>
我的友情链接
查看>>
HAProxy负载均衡原理及企业级实例部署haproxy集群
查看>>
开源中国动弹客户端实践(三)
查看>>
Win 8创造颠覆性体验:预览版关键更新
查看>>
vim在多文件中复制粘贴内容
查看>>
Android ContentObserver
查看>>
文章“关于架构优化和设计,架构师必须知道的事情”
查看>>
疯狂java学习笔记1002---非静态内部类
查看>>
ISA2006实战系列之一:实战ISA三种客户端部署方案(上)
查看>>
TCP服务器
查看>>
U-Mail邮件系统与泛微OA系统一体化操作指南
查看>>
AC旁挂三层交换机管理ap,二层接入ap心得
查看>>
JS中比较数字大小
查看>>
springcloud 学习-eureka搭建-为eureka添加认证
查看>>
jQuery插件的开发
查看>>
基础,基础,还是基础之JAVA基础
查看>>
如何成为一个C++高级程序员
查看>>
ant android 打包签名和渠道
查看>>