`
Donald_Draper
  • 浏览: 955190 次
社区版块
存档分类
最新评论

Jedis获取Redis连接详解

阅读更多
Jedis操作Redis :http://donald-draper.iteye.com/blog/2346958
在前面一章中,我们讲了Jedis如何操作redis,今天我们来看一下他如何操作
从下面这几句开始:
  
 private static JedisPoolConfig jConfig = null;
    private static JedisPool pool = null;  
    private static Jedis jedis = null; 
    static {
    	jConfig = new JedisPoolConfig();
    } 
    public static void init() {  
        pool = new JedisPool(jConfig,"192.168.126.128",6379);
        jedis = pool.getResource();  
        jedis.auth("redis");  
        //测试是否连接成功
        System.out.println("Connecting redis......."+jedis.ping());
    }

上面这段话有几个要点第一点:Jedis连接池配置
jConfig = new JedisPoolConfig();

第二点:jedis连接池初始化
pool = new JedisPool(jConfig,"192.168.126.128",6379);

第三点:从连接池获取jedis连接
jedis = pool.getResource();  
jedis.auth("redis");  
//测试是否连接成功
System.out.println("Connecting redis......."+jedis.ping());


我们先来看第一点
jConfig = new JedisPoolConfig();


import org.apache.commons.pool.impl.GenericObjectPool;
public class JedisPoolConfig extends org.apache.commons.pool.impl.GenericObjectPool.Config
{
    public JedisPoolConfig()
    {
        setTestWhileIdle(true);
        setMinEvictableIdleTimeMillis(60000L);
        setTimeBetweenEvictionRunsMillis(30000L);
        setNumTestsPerEvictionRun(-1);
    }
    public int getMaxIdle()
    {
        return maxIdle;
    }
    public void setMaxIdle(int maxIdle)
    {
        this.maxIdle = maxIdle;
    }
     public int getMinIdle()
    {
        return minIdle;
    }

    public void setMinIdle(int minIdle)
    {
        this.minIdle = minIdle;
    }
      public int getMaxActive()
    {
        return maxActive;
    }
    public void setMaxActive(int maxActive)
    {
        this.maxActive = maxActive;
    }
    public long getMaxWait()
    {
        return maxWait;
    }
    public void setMaxWait(long maxWait)
    {
        this.maxWait = maxWait;
    }
...
}

从JedisPoolConfig我们可以看出,JedisPoolConfig的功能主要是配置连接最大空闲
时间,存活数量,及等待时间;
再来看GenericObjectPool.Config
public class GenericObjectPool extends BaseObjectPool
    implements ObjectPool
{
public static class Config
    {

        public int maxIdle;
        public int minIdle;//空闲时间
        public int maxActive;//存活数量
        public long maxWait;//等待时间
        public byte whenExhaustedAction;
        public boolean testOnBorrow;
        public boolean testOnReturn;
        public boolean testWhileIdle;
        public long timeBetweenEvictionRunsMillis;
        public int numTestsPerEvictionRun;
        public long minEvictableIdleTimeMillis;
        public long softMinEvictableIdleTimeMillis;
        public boolean lifo;

        public Config()
        {
            maxIdle = 8;
            minIdle = 0;
            maxActive = 8;
            maxWait = -1L;
            whenExhaustedAction = 1;
            testOnBorrow = false;
            testOnReturn = false;
            testWhileIdle = false;
            timeBetweenEvictionRunsMillis = -1L;
            numTestsPerEvictionRun = 3;
            minEvictableIdleTimeMillis = 1800000L;
            softMinEvictableIdleTimeMillis = -1L;
            lifo = true;
        }
    }
}

从上可以看出JedisPoolConfig的父类Config为GenericObjectPool的静态内部类,与连接池
有关的属性在Config中,而属性的设置在JedisPoolConfig中;
下面我们来看第二点:
pool = new JedisPool(jConfig,"192.168.126.128",6379);

初始化连接池:
package redis.clients.jedis;

import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import redis.clients.util.Pool;

// Referenced classes of package redis.clients.jedis:
//            BinaryJedis, Jedis

public class JedisPool extends Pool
{
   public JedisPool(org.apache.commons.pool.impl.GenericObjectPool.Config poolConfig, String host, int port)
    {
        this(poolConfig, host, port, 2000, null, 0);
    }
    //最后几个参数为timeout, password, database,超时时间,密码,数据库
    public JedisPool(org.apache.commons.pool.impl.GenericObjectPool.Config poolConfig, String host, int port, int timeout, String password, int database)
    {
        super(poolConfig, new JedisFactory(host, port, timeout, password, database));
    }
}

在来看起父类Pool
public abstract class Pool
{
    private final GenericObjectPool internalPool;//连接池
    public Pool(org.apache.commons.pool.impl.GenericObjectPool.Config poolConfig, PoolableObjectFactory factory)
    {
        internalPool = new GenericObjectPool(factory, poolConfig);
    }
}

再来看一下GenericObjectPool
GenericObjectPool在上面已经出现过,Config为其静态内部类
public class GenericObjectPool extends BaseObjectPool
    implements ObjectPool
{
   public static final byte WHEN_EXHAUSTED_FAIL = 0;
    public static final byte WHEN_EXHAUSTED_BLOCK = 1;
    public static final byte WHEN_EXHAUSTED_GROW = 2;
    public static final int DEFAULT_MAX_IDLE = 8;
    public static final int DEFAULT_MIN_IDLE = 0;
    public static final int DEFAULT_MAX_ACTIVE = 8;
    public static final byte DEFAULT_WHEN_EXHAUSTED_ACTION = 1;
    public static final boolean DEFAULT_LIFO = true;
    public static final long DEFAULT_MAX_WAIT = -1L;
    public static final boolean DEFAULT_TEST_ON_BORROW = false;
    public static final boolean DEFAULT_TEST_ON_RETURN = false;
    public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
    public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
    public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
    public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1800000L;
    public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1L;
    private int _maxIdle;//空闲时间
    private int _minIdle;
    private int _maxActive;//存活数量
    private long _maxWait;//等待时间
    private byte _whenExhaustedAction;
    private volatile boolean _testOnBorrow;
    private volatile boolean _testOnReturn;
    private boolean _testWhileIdle;
    private long _timeBetweenEvictionRunsMillis;
    private int _numTestsPerEvictionRun;
    private long _minEvictableIdleTimeMillis;
    private long _softMinEvictableIdleTimeMillis;
    private boolean _lifo;
    private CursorableLinkedList _pool;//连接池
    private CursorableLinkedList.Cursor _evictionCursor;//候选连接池
    private PoolableObjectFactory _factory;//连接池对象工厂JedisFactory
    private int _numActive;//存活数量
    private Evictor _evictor;//候选连接执行器
    private int _numInternalProcessing;
    private final LinkedList _allocationQueue;//jedis连接获取互斥锁链
    //根据连接池工程和配置初始化GenericObjectPool
 public GenericObjectPool(PoolableObjectFactory factory, Config config)
    {
        this(factory, config.maxActive, config.whenExhaustedAction, config.maxWait, config.maxIdle, config.minIdle, config.testOnBorrow, config.testOnReturn, config.timeBetweenEvictionRunsMillis, config.numTestsPerEvictionRun, config.minEvictableIdleTimeMillis, config.testWhileIdle, config.softMinEvictableIdleTimeMillis, config.lifo);
    }
    public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int minIdle, 
            boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, 
            boolean testWhileIdle, long softMinEvictableIdleTimeMillis, boolean lifo)
    {
        _maxIdle = 8;
        _minIdle = 0;
        _maxActive = 8;
        _maxWait = -1L;
        _whenExhaustedAction = 1;
        _testOnBorrow = false;
        _testOnReturn = false;
        _testWhileIdle = false;
        _timeBetweenEvictionRunsMillis = -1L;
        _numTestsPerEvictionRun = 3;
        _minEvictableIdleTimeMillis = 1800000L;
        _softMinEvictableIdleTimeMillis = -1L;
        _lifo = true;
        _pool = null;
        _evictionCursor = null;
        _factory = null;
        _numActive = 0;//存活连接数量
        _evictor = null;
        _numInternalProcessing = 0;
        _allocationQueue = new LinkedList();
        _factory = factory;//连接池对象工厂
        _maxActive = maxActive;//最大存活数量
        _lifo = lifo;
        switch(whenExhaustedAction)
        {
        case 0: // '\0'
        case 1: // '\001'
        case 2: // '\002'
            _whenExhaustedAction = whenExhaustedAction;
            break;

        default:
            throw new IllegalArgumentException((new StringBuilder()).append("whenExhaustedAction ").append(whenExhaustedAction).append(" not recognized.").toString());
        }
        _maxWait = maxWait;
        _maxIdle = maxIdle;
        _minIdle = minIdle;//空闲、等待时间
        _testOnBorrow = testOnBorrow;
        _testOnReturn = testOnReturn;
        _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
        _numTestsPerEvictionRun = numTestsPerEvictionRun;
        _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
        _softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
        _testWhileIdle = testWhileIdle;
	//class CursorableLinkedList implements List, Serializable,存放连接
        _pool = new CursorableLinkedList();
	//由于_evictor为空和_timeBetweenEvictionRunsMillis为-1L,这时候startEvictor没做任何事情
        startEvictor(_timeBetweenEvictionRunsMillis);
    }

}

//启动候选连接执行器
 protected synchronized void startEvictor(long delay)
    {
        if(null != _evictor)
        {
            EvictionTimer.cancel(_evictor);
            _evictor = null;
        }
        if(delay > 0L)
        {
            _evictor = new Evictor();
            EvictionTimer.schedule(_evictor, delay, delay);
        }

//GenericObjectPool内部类Evictor
 private class Evictor extends TimerTask
    {
        public void run()
        {
            try
            {
                //从连接池获取,候选连接池,并分配连接句柄
		evict();
            }
            catch(Exception e) { }
            catch(OutOfMemoryError oome)
            {
                oome.printStackTrace(System.err);
            }
            try
            {
                ensureMinIdle();
            }
            catch(Exception e) { }
        }
        final GenericObjectPool this$0;

        private Evictor()
        {
            this$0 = GenericObjectPool.this;
            super();
        }
    }
    public void evict()
        throws Exception
    {
        //如果候选连接为空,则从连接池中获取连接最为候选连接
        if(null == _evictionCursor)
            _evictionCursor = _pool.cursor(_lifo ? _pool.size() : 0);
        
        allocate();
        return;
    }
    //分配连接获取锁
    private synchronized void allocate()
    {
        if(isClosed())
            return;
        while(!_pool.isEmpty() && !_allocationQueue.isEmpty()) 
        {
            Latch latch = (Latch)_allocationQueue.removeFirst();
            latch.setPair((GenericKeyedObjectPool.ObjectTimestampPair)_pool.removeFirst());
            _numInternalProcessing++;
            synchronized(latch)
            {
                latch.notify();
            }
        }
        while(!_allocationQueue.isEmpty() && (_maxActive < 0 || _numActive + _numInternalProcessing < _maxActive)) 
        {
            Latch latch = (Latch)_allocationQueue.removeFirst();
            latch.setMayCreate(true);
            _numInternalProcessing++;
            synchronized(latch)
            {
                latch.notify();
            }
        }
}

从上面可看出,GenericObjectPool初始化,主要是初始化连接池,连接数,空闲时间,等待时间,连接池,候选连接池,初始化候选连接初始化执行器。
我们再看看一下JedisFactory
public class JedisPool extends Pool
{
    private static class JedisFactory extends BasePoolableObjectFactory
    {

        //构造Redis客户连接Jedis
	public Object makeObject()
            throws Exception
        {
	     //构建Jedis
            Jedis jedis = new Jedis(host, port, timeout);
            jedis.connect();
            if(null != password)
	        //密码不为空则,校验
                jedis.auth(password);
            if(database != 0)
	        //选择数据库
                jedis.select(database);
            return jedis;
        }
        //关闭Jedis连接
        public void destroyObject(Object obj)
            throws Exception
        {
            if(obj instanceof Jedis)
            {
                Jedis jedis = (Jedis)obj;
                if(jedis.isConnected())
                    try
                    {
                        try
                        {
                            jedis.quit();
                        }
                        catch(Exception e) { }
                        jedis.disconnect();
                    }
                    catch(Exception e) { }
            }
        }
       //验证Jedis连接
        public boolean validateObject(Object obj)
        {
            Jedis jedis;
            if(!(obj instanceof Jedis))
                break MISSING_BLOCK_LABEL_40;
            jedis = (Jedis)obj;
            return jedis.isConnected() && jedis.ping().equals("PONG");
            Exception e;
            e;
            return false;
            return false;
        }

        private final String host;//ip
        private final int port;//端口号
        private final int timeout;//超时时间
        private final String password;//密码
        private final int database;//数据库

        public JedisFactory(String host, int port, int timeout, String password, int database)
        {
            this.host = host;
            this.port = port;
            this.timeout = timeout;
            this.password = password;
            this.database = database;
        }
    }
}

从上面可以看出JedisFactory工厂为JedisPool的内部类,JedisFactory的属性有host,port,timeout,password和database;JedisFactory的主要功能为管理(创建,关闭,验证)redis连接jedis。
现在我们来看第三点
第三点:从连接池获取jedis连接
jedis = pool.getResource();  
jedis.auth("redis");  
//测试是否连接成功
System.out.println("Connecting redis......."+jedis.ping());


从连接池获取jedis连接资源
jedis = pool.getResource();

此方法在JedisPool在父类Pool中
public abstract class Pool
{

    public Pool(org.apache.commons.pool.impl.GenericObjectPool.Config poolConfig, PoolableObjectFactory factory)
    {
        internalPool = new GenericObjectPool(factory, poolConfig);
    }
    //从连接池GenericObjectPool,获取jedis连接资源
    public Object getResource()
    {
        return internalPool.borrowObject();
    }
}

再来看GenericObjectPool的borrowObject的方法
//GenericObjectPool
public Object borrowObject()
        throws Exception
    {
        long starttime;
        Latch latch;
        byte whenExhaustedAction;
        long maxWait;
        starttime = System.currentTimeMillis();
        latch = new Latch();
        synchronized(this)
        {
            whenExhaustedAction = _whenExhaustedAction;
            maxWait = _maxWait;
	    //将连接获取锁添加到连接分配锁队列
            _allocationQueue.add(latch);
        }
        allocate();
	...
	//关键在这一句从上面,我们看出_factory为JedisFactory,JedisFactory的makeObject返回的是Jedis连接
	Object obj = _factory.makeObject();
        latch.setPair(new ObjectTimestampPair(obj));
	...
	 _factory.activateObject(latch.getPair().value);
	//如果连接获取开关_testOnBorrow打开,则验证连接
	 if(_testOnBorrow && !_factory.validateObject(latch.getPair().value))
            throw new Exception("ValidateObject failed");
	 //返回jedis客户端
	 return latch.getPair().value;
}

再看borrowObject方法的这两句
latch.setPair(new ObjectTimestampPair(obj));

//ObjectTimestampPair,带时间戳的对象
  static class ObjectTimestampPair
        implements Comparable
    {

        public String toString()
        {
            return (new StringBuilder()).append(value).append(";").append(tstamp).toString();
        }

        public int compareTo(Object obj)
        {
            return compareTo((ObjectTimestampPair)obj);
        }

        public int compareTo(ObjectTimestampPair other)
        {
            long tstampdiff = tstamp - other.tstamp;
            if(tstampdiff == 0L)
                return System.identityHashCode(this) - System.identityHashCode(other);
            else
                return (int)Math.min(Math.max(tstampdiff, -2147483648L), 2147483647L);
        }

        public Object getValue()
        {
            return value;
        }

        public long getTstamp()
        {
            return tstamp;
        }

        /**
         * @deprecated Field value is deprecated
         */
        Object value;
        /**
         * @deprecated Field tstamp is deprecated
         */
        long tstamp;

        ObjectTimestampPair(Object val)
        {
            this(val, System.currentTimeMillis());
        }

        ObjectTimestampPair(Object val, long time)
        {
            value = val;
            tstamp = time;
        }
    }
 }
//Latch
public class GenericObjectPool extends BaseObjectPool
    implements ObjectPool
{
    //连接获取锁
    private static final class Latch
    {

        private synchronized GenericKeyedObjectPool.ObjectTimestampPair getPair()
        {
            return _pair;
        }

        private synchronized void setPair(GenericKeyedObjectPool.ObjectTimestampPair pair)
        {
            _pair = pair;
        }

        private synchronized boolean mayCreate()
        {
            return _mayCreate;
        }

        private synchronized void setMayCreate(boolean mayCreate)
        {
            _mayCreate = mayCreate;
        }

        private synchronized void reset()
        {
            _pair = null;
            _mayCreate = false;
        }

        private GenericKeyedObjectPool.ObjectTimestampPair _pair;
        private boolean _mayCreate;
        private Latch()
        {
            _mayCreate = false;
        }

    }
}

从连接池获取jedis连接资源,实际上看是从pool中获取,而pool又委托给JedisFactory,
最后由JedisFactory创建redis连接jedis。
这一节我们就看到这里
总结:
JedisPoolConfig的功能主要是配置连接最大空闲时间,存活数量,及等待时间;
JedisPoolConfig的父类Config为GenericObjectPool的静态内部类,与连接池有关的属性在Config中,而属性的设置在JedisPoolConfig中;JedisPool的初始化主要是GenericObjectPool初始化,主要是初始化连接池,连接数,空闲时间,等待时间,连接池,候选连接池,初始化候选连接初始化执行器,JedisFactory。JedisFactory工厂为JedisPool的内部类,JedisFactory的属性有host,port,timeout,password和database;JedisFactory的主要功能为管理(创建,关闭,验证)redis连接jedis。从连接池获取jedis连接资源,实际上看是从JedisPool的父类pool中获取,而pool又委托给JedisFactory,最后由JedisFactory创建redis连接jedis。
0
0
分享到:
评论

相关推荐

    Redis 、Redis 连接池、JedisPool

    1.全网最强最好用redis 封装连接池,redis 配置详解 2.jar 内置最全 最安全的两种redis 连接池 创建方式(synchronized and look), 3.通过了自己公司生产环境的检测 4.使用方法:只需要将jar 放入项目 lib 下面 ...

    redis使用详解

    直接使用redis源码,使用socket直接访问redis案例,redis连接池使用案例,sentinel连接池使用案例,redis集群连接池的案例

    Jedis对redis的五大类型操作代码详解

    主要介绍了Jedis对redis的五大操作代码详解,分别是字符串、列表、散列、集合、有序集合,具有一定参考价值,需要的朋友可以了解下。

    Redis6课程大纲.xmind

    涵盖了NoSQL数据库的简介、Redis6的概述和安装、常用的五大数据类型、Redis6的配置文件详解、Redis6的发布和订阅、Redis6新数据类型、Jedis操作Redis等16各部分。

    【Redis缓存机制】详解Java连接Redis_Jedis_事务

    主要介绍了【Redis缓存机制】详解Java连接Redis_Jedis_事务,详细的介绍了Jedis事务和实例,有兴趣的可以了解一下。

    详解Redis开启远程登录连接

    今天使用jedis客户端api连接远程连接redis的时候,一直报错,如下: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect at redis.clients.jedis...

    jedis配置含义详解

    jedis就是基于java语言的redis客户端,集成了redis的命令操作,提供了连接池管理。 jedis连接池 预先生成一批jedis连接对象放入连接池中,当需要对redis进行操作时从连接池中借用jedis对象,操作完成后归还。这样...

    Redis官方Cluster搭建配置步骤详解

    Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。 Redis集群并 不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误. ...

    redis学习文档

    redis测试数据.xlsx redis第二节课-Redis Cluster.doc redis第三节课-Jedis详解.doc redis第四节课.doc redis第五节课redis脑图.doc redis.conf文件详解.docx 部署文档.docx NoSql之redis演变过程.pdf

    详解java 客户端链接不上redis解决方案

    主要介绍了详解java 客户端链接不上redis解决方案,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。

    详解SSH框架和Redis的整合

    一个已有的Struts+Spring+Hibernate项目,以前使用MySQL...在src文件夹下面新建一个redis.properties文件,设置连接Redis的一些属性。 redis.host=127.0.0.1 redis.port=6379 redis.default.db=1 redis.timeout=1000

    Redis协议具体用法详解

    前言 我们用过很多redis的客户端,有...public class RedisTest { public static void main(String[] args) { Jedis jedis = new Jedis(127.0.0.1, 6379); jedis.set(eat, I want to eat); }} 监听socket: public s

    Redis如何存储对象与集合示例详解

    这里主要讲redis如何把对象,集合存入,并且取出。下面话不多说了,来一起看看详细的介绍吧。 1.在启动类上加入如下代码 private Jedis jedis;private JedisPoolConfig config;private JedisShardInfo sharInfo;@...

    redis命令参考-新.docx

    redis学习指南中介绍了什么是NOSQL,NOSQL产生背景,Redis由来及应用场景,基础安装、命令使用,持久化策略,JAVA API Jedis的基本使用,Redis配置文件详解,Redis与同类产品的比较

    Jedis2.8Demo文件-从数据类型到订阅部分

    分为两个部分: 1.获取连接池.创建redis实例 2.字符串、哈希、列表、集合、有序集合、HyperLogLog、发布与订阅这部分操作文档 详解,运行方法可见结果~

    心跳机制详解

    心跳机制详解

    Redis中键值过期操作示例详解

    Redis 中设置过期时间主要通过以下四种方式: expire key seconds:设置 key 在 n 秒后过期; pexpire key milliseconds:设置 key 在 n 毫秒后过期; expireat key timestamp:设置 key 在某个时间戳(精确到秒...

    Tomcat Nginx Redis实现session共享过程图解

    jar包:commons-pool2-2.4.2.jar、jedis-2.8.0.jar、tomcat-redis-session-manager-2.0.0.jar 二、配置Tomcat 多台Tomacat需要配置不同的端口号 /lib 将jar包存放到此位置 /conf/server.xml ​ ​ /conf/context.xml...

Global site tag (gtag.js) - Google Analytics