jedis的borrow行为方法源码解读

 更新时间:2023年09月22日 10:33:41   作者:codecraft  
这篇文章主要为大家介绍了jedis的borrow行为方法源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

本文主要研究一下jedis的borrow行为

borrowObject

org/apache/commons/pool2/impl/GenericObjectPool.java

public T borrowObject(final Duration borrowMaxWaitDuration) throws Exception {
        assertOpen();
        final 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
        final boolean blockWhenExhausted = getBlockWhenExhausted();
        boolean create;
        final long waitTimeMillis = System.currentTimeMillis();
        while (p == null) {
            create = false;
            p = idleObjects.pollFirst();
            if (p == null) {
                p = create();
                if (p != null) {
                    create = true;
                }
            }
            if (blockWhenExhausted) {
                if (p == null) {
                    if (borrowMaxWaitDuration.isNegative()) {
                        p = idleObjects.takeFirst();
                    } else {
                        p = idleObjects.pollFirst(borrowMaxWaitDuration);
                    }
                }
                if (p == null) {
                    throw new NoSuchElementException(appendStats(
                            "Timeout waiting for idle object, borrowMaxWaitDuration=" + borrowMaxWaitDuration));
                }
            } else if (p == null) {
                throw new NoSuchElementException(appendStats("Pool exhausted"));
            }
            if (!p.allocate()) {
                p = null;
            }
            if (p != null) {
                try {
                    factory.activateObject(p);
                } catch (final Exception e) {
                    try {
                        destroy(p, DestroyMode.NORMAL);
                    } catch (final Exception e1) {
                        // Ignore - activation failure is more important
                    }
                    p = null;
                    if (create) {
                        final NoSuchElementException nsee = new NoSuchElementException(
                                appendStats("Unable to activate object"));
                        nsee.initCause(e);
                        throw nsee;
                    }
                }
                if (p != null && getTestOnBorrow()) {
                    boolean validate = false;
                    Throwable validationThrowable = null;
                    try {
                        validate = factory.validateObject(p);
                    } catch (final Throwable t) {
                        PoolUtils.checkRethrow(t);
                        validationThrowable = t;
                    }
                    if (!validate) {
                        try {
                            destroy(p, DestroyMode.NORMAL);
                            destroyedByBorrowValidationCount.incrementAndGet();
                        } catch (final Exception e) {
                            // Ignore - validation failure is more important
                        }
                        p = null;
                        if (create) {
                            final NoSuchElementException nsee = new NoSuchElementException(
                                    appendStats("Unable to validate object"));
                            nsee.initCause(validationThrowable);
                            throw nsee;
                        }
                    }
                }
            }
        }
        updateStatsBorrow(p, Duration.ofMillis(System.currentTimeMillis() - waitTimeMillis));
        return p.getObject();
    }
  • borrowObject方法会开启一个while循环,条件是p为null,也就是要获取到p或者是内部自己跳出循环;idleObjects.pollFirst()从连接池获取,如果为null则执行create,之后是blockWhenExhausted的判断逻辑,如果create出来的为null,则阻塞等待takeFirst或者pollFirst(borrowMaxWaitDuration),如果还是null则抛出NoSuchElementException;如果blockWhenExhausted为false但是create为null则抛出Pool exhausted
  • 如果不是null,则再次确认下object的状态,如果变更状态(PooledObjectState.IDLE-->PooledObjectState.ALLOCATED)不成功则返回null;接着执行factory.activateObject(p)方法,如果出现异常则destory掉(jedis这里只是在db不一样的时候会重新select,默认可以理解为空操作),紧接着是testOnBorrow的逻辑
  • 这里就是如果idleObjects.pollFirst()为null会触发create,如果还是null则直接抛出NoSuchElementException异常,跳出循环;只有在不为null且allocate失败的时候会重置为null继续循环;另外如果是create出来的但是activate不成功也会抛出NoSuchElementException异常,跳出循环

create

/**
     * Attempts to create a new wrapped pooled object.
     * <p>
     * If there are {@link #getMaxTotal()} objects already in circulation
     * or in process of being created, this method returns null.
     * </p>
     *
     * @return The new wrapped pooled object
     *
     * @throws Exception if the object factory's {@code makeObject} fails
     */
    private PooledObject<T> create() throws Exception {
        int localMaxTotal = getMaxTotal();
        // This simplifies the code later in this method
        if (localMaxTotal < 0) {
            localMaxTotal = Integer.MAX_VALUE;
        }
        final long localStartTimeMillis = System.currentTimeMillis();
        final long localMaxWaitTimeMillis = Math.max(getMaxWaitDuration().toMillis(), 0);
        // Flag that indicates if create should:
        // - TRUE:  call the factory to create an object
        // - FALSE: return null
        // - null:  loop and re-test the condition that determines whether to
        //          call the factory
        Boolean create = null;
        while (create == null) {
            synchronized (makeObjectCountLock) {
                final long newCreateCount = createCount.incrementAndGet();
                if (newCreateCount > localMaxTotal) {
                    // The pool is currently at capacity or in the process of
                    // making enough new objects to take it to capacity.
                    createCount.decrementAndGet();
                    if (makeObjectCount == 0) {
                        // There are no makeObject() calls in progress so the
                        // pool is at capacity. Do not attempt to create a new
                        // object. Return and wait for an object to be returned
                        create = Boolean.FALSE;
                    } else {
                        // There are makeObject() calls in progress that might
                        // bring the pool to capacity. Those calls might also
                        // fail so wait until they complete and then re-test if
                        // the pool is at capacity or not.
                        makeObjectCountLock.wait(localMaxWaitTimeMillis);
                    }
                } else {
                    // The pool is not at capacity. Create a new object.
                    makeObjectCount++;
                    create = Boolean.TRUE;
                }
            }
            // Do not block more if maxWaitTimeMillis is set.
            if (create == null &&
                (localMaxWaitTimeMillis > 0 &&
                 System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) {
                create = Boolean.FALSE;
            }
        }
        if (!create.booleanValue()) {
            return null;
        }
        final PooledObject<T> p;
        try {
            p = factory.makeObject();
            if (getTestOnCreate() && !factory.validateObject(p)) {
                createCount.decrementAndGet();
                return null;
            }
        } catch (final Throwable e) {
            createCount.decrementAndGet();
            throw e;
        } finally {
            synchronized (makeObjectCountLock) {
                makeObjectCount--;
                makeObjectCountLock.notifyAll();
            }
        }
        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getLogAbandoned()) {
            p.setLogAbandoned(true);
            p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
        }
        createdCount.incrementAndGet();
        allObjects.put(new IdentityWrapper<>(p.getObject()), p);
        return p;
    }
create方法不会判断createCount,如果超出则返回null,如果等待超出maxWait也会返回null;如果判断要创建则通过factory.makeObject(),另外针对testOnCreate且validateObject不通过的也返回null,如果是有异常则直接抛出

makeObject

redis/clients/jedis/JedisFactory.java

@Override
  public PooledObject<Jedis> makeObject() throws Exception {
    Jedis jedis = null;
    try {
      jedis = new Jedis(jedisSocketFactory, clientConfig);
      jedis.connect();
      return new DefaultPooledObject<>(jedis);
    } catch (JedisException je) {
      if (jedis != null) {
        try {
          jedis.quit();
        } catch (RuntimeException e) {
          logger.warn("Error while QUIT", e);
        }
        try {
          jedis.close();
        } catch (RuntimeException e) {
          logger.warn("Error while close", e);
        }
      }
      throw je;
    }
  }
JedisFactory的makeObject会创建Jedis然后执行connect,如果有JedisException则抛出,这个也会直接跳出borrowObject的循环,直接给到调用方

activateObject

redis/clients/jedis/JedisFactory.java

public void activateObject(PooledObject<Jedis> pooledJedis) throws Exception {
    final BinaryJedis jedis = pooledJedis.getObject();
    if (jedis.getDB() != clientConfig.getDatabase()) {
      jedis.select(clientConfig.getDatabase());
    }
  }
JedisFactory的activateObject就是判断db跟配置的是不是一样,不一样则重新select

testOnBorrow

if (p != null && getTestOnBorrow()) {
                    boolean validate = false;
                    Throwable validationThrowable = null;
                    try {
                        validate = factory.validateObject(p);
                    } catch (final Throwable t) {
                        PoolUtils.checkRethrow(t);
                        validationThrowable = t;
                    }
                    if (!validate) {
                        try {
                            destroy(p, DestroyMode.NORMAL);
                            destroyedByBorrowValidationCount.incrementAndGet();
                        } catch (final Exception e) {
                            // Ignore - validation failure is more important
                        }
                        p = null;
                        if (create) {
                            final NoSuchElementException nsee = new NoSuchElementException(
                                    appendStats("Unable to validate object"));
                            nsee.initCause(validationThrowable);
                            throw nsee;
                        }
                    }
                }
    public static void checkRethrow(final Throwable t) {
        if (t instanceof ThreadDeath) {
            throw (ThreadDeath) t;
        }
        if (t instanceof VirtualMachineError) {
            throw (VirtualMachineError) t;
        }
        // All other instances of Throwable will be silently swallowed
    }
testOnBorrow的逻辑就是执行validateObject方法,如果是ThreadDeath或者VirtualMachineError才会重新抛出,否则吞掉,之后判断validate结果,如果不成功则执行destory方法,重新设置为null,但是如果这个是create出来的则抛出NoSuchElementException

小结

jedis的borrow行为是在while循环里头去获取的,一般是在allocate变更状态不成功(PooledObjectState.IDLE-->PooledObjectState.ALLOCATED)的时候会重新设置null,继续循环

  • idleObjects.pollFirst()为null会触发create,如果还是null则抛出NoSuchElementException(Pool exhausted)跳出循环;如果blockWhenExhausted为true,block之后获取到的还是null,也会抛出NoSuchElementException(Timeout waiting for idle object)跳出循环;如果触发create操作,且create抛出JedisException,这个也会直接跳出borrowObject的循环,直接给到调用方
  • borrow出来不会null的执行activateObject,jedis这里只是在db不一样的时候会重新select,默认可以理解为空操作

最后是testOnBorrow的逻辑,如果有异常,则针对create出来的则抛出NoSuchElementException跳出循环,否则重置为null继续循环

总结

一下就是如果是create有异常(JedisException)则直接抛出,如果borrow不到(即使经过create)也会抛出NoSuchElementException(具体可能是Pool exhausted或者Timeout waiting for idle object),如果有testOnBorrow不通过且是create出来的,也会抛出NoSuchElementException(Unable to validate object)

以上就是jedis的borrow行为方法源码解读的详细内容,更多关于jedis borrow方法的资料请关注脚本之家其它相关文章!

相关文章

  • Java虚拟机JVM性能优化(二):编译器

    Java虚拟机JVM性能优化(二):编译器

    这篇文章主要介绍了Java虚拟机JVM性能优化(二):编译器,本文先是讲解了不同种类的编译器,并对客户端编译,服务器端编译器和多层编译的运行性能进行了对比,然后给出了几种常见的JVM优化方法,需要的朋友可以参考下
    2014-09-09
  • Java如何实现简单的RPC框架

    Java如何实现简单的RPC框架

    这篇文章主要介绍了Java如何实现简单的RPC框架,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • Java实现简单员工管理系统

    Java实现简单员工管理系统

    这篇文章主要为大家详细介绍了Java实现简单员工管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • SpringBoot 内嵌 camunda的配置方法

    SpringBoot 内嵌 camunda的配置方法

    Camunda是一个基于Java的框架,支持用于工作流和流程自动化的BPMN、用于案例管理的CMMN和用于业务决策管理的DMN,这篇文章主要介绍了SpringBoot 内嵌 camunda,需要的朋友可以参考下
    2024-06-06
  • SpringBoot3整合Druid的兼容性问题解决方案

    SpringBoot3整合Druid的兼容性问题解决方案

    Druid对于SpringBoot3的支持不够全面和友好;存在一些兼容性的问题,导致项目报错,所以本文小编给大家介绍了如何解决SpringBoot3整合Druid的兼容性问题,需要的朋友可以参考下
    2023-09-09
  • 关于Spring启动流程及Bean生命周期梳理

    关于Spring启动流程及Bean生命周期梳理

    这篇文章主要介绍了关于Spring启动流程及Bean生命周期梳理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java事务管理学习之JDBC详解

    Java事务管理学习之JDBC详解

    这篇文章主要介绍了Java事务管理学习之JDBC的相关资料,文中介绍的非常详细,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-03-03
  • SpringBoot接口数据如何实现优雅的脱敏问题

    SpringBoot接口数据如何实现优雅的脱敏问题

    这篇文章主要介绍了SpringBoot接口数据如何实现优雅的脱敏问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • SpringBoot Security使用MySQL实现验证与权限管理

    SpringBoot Security使用MySQL实现验证与权限管理

    安全管理是软件系统必不可少的的功能。根据经典的“墨菲定律”——凡是可能,总会发生。如果系统存在安全隐患,最终必然会出现问题,这篇文章主要介绍了SpringBoot安全管理Spring Security基本配置
    2022-11-11
  • Java微信公众平台开发(5) 文本及图文消息回复的实现

    Java微信公众平台开发(5) 文本及图文消息回复的实现

    这篇文章主要为大家详细介绍了Java微信公众平台开发第五步,回文本及图文消息回复的实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04

最新评论