JedisPool源码解析

Posted 低调的洋仔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JedisPool源码解析相关的知识,希望对你有一定的参考价值。

JedisPoolConfig的继承结构

这个BaseObjectPoolConfig中无非是一部分常量和私有的变量。

 

public abstract class BaseObjectPoolConfig implements Cloneable 
    public static final boolean DEFAULT_LIFO = true;
    public static final boolean DEFAULT_FAIRNESS = false;
    public static final long DEFAULT_MAX_WAIT_MILLIS = -1L;
    public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1800000L;
    public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1L;
    public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
    public static final boolean DEFAULT_TEST_ON_CREATE = false;
    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 boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;
    public static final boolean DEFAULT_JMX_ENABLE = true;
    public static final String DEFAULT_JMX_NAME_PREFIX = "pool";
    public static final String DEFAULT_JMX_NAME_BASE = null;
    public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = "org.apache.commons.pool2.impl.DefaultEvictionPolicy";
    private boolean lifo = true;
    private boolean fairness = false;
    private long maxWaitMillis = -1L;
    private long minEvictableIdleTimeMillis = 1800000L;
    private long softMinEvictableIdleTimeMillis = 1800000L;
    private int numTestsPerEvictionRun = 3;
    private String evictionPolicyClassName = "org.apache.commons.pool2.impl.DefaultEvictionPolicy";
    private boolean testOnCreate = false;
    private boolean testOnBorrow = false;
    private boolean testOnReturn = false;
    private boolean testWhileIdle = false;
    private long timeBetweenEvictionRunsMillis = -1L;
    private boolean blockWhenExhausted = true;
    private boolean jmxEnabled = true;
    private String jmxNamePrefix = "pool";
    private String jmxNameBase = "pool";


然后它的子类补充了部分的常量和变量。

 

 

public class GenericObjectPoolConfig extends BaseObjectPoolConfig 
    public static final int DEFAULT_MAX_TOTAL = 8;
    public static final int DEFAULT_MAX_IDLE = 8;
    public static final int DEFAULT_MIN_IDLE = 0;
    private int maxTotal = 8;
    private int maxIdle = 8;
    private int minIdle = 0;

然后实际初始化的是其构造方法。都是写死的。

 

 

public JedisPoolConfig() 
        this.setTestWhileIdle(true);
        this.setMinEvictableIdleTimeMillis(60000L);
        this.setTimeBetweenEvictionRunsMillis(30000L);
        this.setNumTestsPerEvictionRun(-1);
    

 

例子

 JedisPoolConfig config = new JedisPoolConfig();
        config.setTestOnBorrow(true);
        pool = new JedisPool(config, "", 2181, 2000, "foobared");
        jedis = pool.getResource();
        jedis.set("foo", "bar");
        jedis.close();

 

Config部分创建了一个配置项实例。

 

设置部分参数可以。

然后这个地方创建了一个JedisPool的实例,这个实例,

    public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database) 
        this(poolConfig, host, port, timeout, password, database, (String)null);
    

    public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database, String clientName) 
        super(poolConfig, new JedisFactory(host, port, timeout, password, database, clientName));
    

JedisPool调用了父类的方法、

集成体系,JedisPool继承自Pool这个类,

 

    public Pool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) 
        this.initPool(poolConfig, factory);
    

    public void initPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) 
        if (this.internalPool != null) 
            try 
                this.closeInternalPool();
             catch (Exception var4) 
                ;
            
        
        this.internalPool = new GenericObjectPool(factory, poolConfig);
    

调用Pool中的初始化pool方法。

 

这个方法中是调用了

 
GenericObjectPool
 
/** * Create a new <code>GenericObjectPool</code> using a specific * configuration. */ public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config)  super(config, ONAME_BASE, config.getJmxNamePrefix()); if (factory == null)  jmxUnregister(); // tidy up throw new IllegalArgumentException("factory may not be null");  this.factory = factory; idleObjects = new LinkedBlockingDeque<PooledObject<T>>(config.getFairness()); setConfig(config); startEvictor(getTimeBetweenEvictionRunsMillis());// 延迟一定的时间后设置逐出者。 

初始化的GenericObjectPool

注意这里的重点是使用了LinkedBlockingDeque了,也就是双向链表实现的双端队列。空闲的连接放在这里面。
 
 
JedisPool中的方法。
getResource部分
获取空闲的连接、
 
public Jedis getResource()  Jedis jedis = (Jedis)super.getResource(); jedis.setDataSource(this); return jedis;  
 

调用了Pool中的方法。

    public T getResource() 
        try 
            return this.internalPool.borrowObject();
         catch (Exception var2) 
            throw new JedisConnectionException("Could not get a resource from the pool", var2);
        
    

调用GenericObjectPool中的方法

 
@Override public T borrowObject() throws Exception  return borrowObject(getMaxWaitMillis()); 

 

 

    public T borrowObject(long borrowMaxWaitMillis) throws Exception 
        assertOpen();

        AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
                (getNumIdle() < 2) &&
                (getNumActive() > getMaxTotal() - 3) ) 
            removeAbandoned(ac);
        

        PooledObject<T> p = null;

        // Get local copy of current config so it is consistent for entire
        // method execution
        boolean blockWhenExhausted = getBlockWhenExhausted();

        boolean create;
        long waitTime = System.currentTimeMillis();

        while (p == null) 
            create = false;
            if (blockWhenExhausted) 
                p = idleObjects.pollFirst();
                if (p == null) 
                    p = create();
                    if (p != null) 
                        create = true;
                    
                
                if (p == null) 
                    if (borrowMaxWaitMillis < 0) 
                        p = idleObjects.takeFirst();
                     else 
                        p = idleObjects.pollFirst(borrowMaxWaitMillis,
                                TimeUnit.MILLISECONDS);
                    
                
                if (p == null) 
                    throw new NoSuchElementException(
                            "Timeout waiting for idle object");
                
                if (!p.allocate()) 
                    p = null;
                
             else 
                p = idleObjects.pollFirst();
                if (p == null) 
                    p = create();
                    if (p != null) 
                        create = true;
                    
                
                if (p == null) 
                    throw new NoSuchElementException("Pool exhausted");
                
                if (!p.allocate()) 
                    p = null;
                
            

            if (p != null) 
                try 
                    factory.activateObject(p);
                 catch (Exception e) 
                    try 
                        destroy(p);
                     catch (Exception e1) 
                        // Ignore - activation failure is more important
                    
                    p = null;
                    if (create) 
                        NoSuchElementException nsee = new NoSuchElementException(
                                "Unable to activate object");
                        nsee.initCause(e);
                        throw nsee;
                    
                
                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;
                        
                    
                
            
        

        updateStatsBorrow(p, System.currentTimeMillis() - waitTime);// 这里还带了延时的功能

        return p.getObject();
    pollFirst(borrowMaxWaitMillis,
                                TimeUnit.MILLISECONDS);
                    
                
                if (p == null) 
                    throw new NoSuchElementException(
                            "Timeout waiting for idle object");
                
                if (!p.allocate()) 
                    p = null;
                
             else 
                p = idleObjects.pollFirst();
                if (p == null) 
                    p = create();
                    if (p != null) 
                        create = true;
                    
                
                if (p == null) 
                    throw new NoSuchElementException("Pool exhausted");
                
                if (!p.allocate()) 
                    p = null;
                
            

            if (p != null) 
                try 
                    factory.activateObject(p);
                 catch (Exception e) 
                    try 
                        destroy(p);
                     catch (Exception e1) 
                        // Ignore - activation failure is more important
                    
                    p = null;
                    if (create) 
                        NoSuchElementException nsee = new NoSuchElementException(
                                "Unable to activate object");
                        nsee.initCause(e);
                        throw nsee;
                    
                
                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;
                        
                    
                
            
        

        updateStatsBorrow(p, System.currentTimeMillis() - waitTime);// 这里还带了延时的功能

        return p.getObject();
    


然后剩下的就是jedis本身的操作了。

 

 

 
最后理清思路,首先是创建一个JedisPool的实例,这个实例会调用父类Pool中的方法来创建Pool,然后这个Pool中有一个internalPool,使得其等于一个GenericJedisPool,然后这个pool实际上空闲的会存储在LinkedBlockingDeque中去,然后在getResource的时候,会调jedisPool的方法然后调用父类的方法然后调用GenericPool的方法,然后就可以直接获取到空闲线程了。
 
@Override public E pollFirst()  lock.lock(); try  return unlinkFirst();  finally  lock.unlock();  

 

private E unlinkFirst() 
        // assert lock.isHeldByCurrentThread();
        Node<E> f = first;
        if (f == null) 
            return null;
        
        Node<E> n = f.next;
        E item = f.item;
        f.item = null;
        f.next = f; // help GC
        first = n;
        if (n == null) 
            last = null;
         else 
            n.prev = null;
        
        --count;
        notFull.signal();
        return item;
    

直接用的condition类的方法来实现的。

 
 

 

 

 

 

 

以上是关于JedisPool源码解析的主要内容,如果未能解决你的问题,请参考以下文章

datax源码解析-datax的hook机制解析

datax源码解析-datax的hook机制解析

JedisPool(Redis连接池demo)

Jedis源码解析

Jedis源码解析

JedisPool配置详解