commons-pool2自定义对象池-快速开始

本文深入解析了Apache commons-pool2库,介绍了如何利用它自定义对象池,特别是链接池的实现原理。并通过分析JedisPool源码,详细阐述了Jedis如何高效地使用commons-pool2实现连接池,包括JedisPool的继承结构、配置参数及JedisFactory的作用。

一、什么是commons-pool2

利用commons-pool2自定义对象池

commons-pool2是Apache下一个开源的公共资源池。我们可以根据它来快速的建立一个自己的对象池。

  • 链接池/对象池(ObjectPool):用于存放链接对象的一个池子(集合),通常用数组或者List对象.durid用两个数组分别保存活跃的链接和空闲链接.commons-pool2用双端阻塞队列LinkedBlockingDeque保存空闲链接
    用ConcurrentHashMap保存所有的链接.

  • 对象工厂(PooledObjectFactory):连接池工厂,用于产生一个新的链接对象.

  • 链接对象/池中对象(PooledObject):链接池里面存放的对象.

核心类:

  1. PooledObjectFactory【对象工厂】,用于产生一个新对象。
  2. ObjectPool【链接池】,用于存放链接对象的一个池子,提供接口用于对象的借取和归还。
  3. PooledObject【链接对象】,链接池内的对象。

1. springboot使用commons-pool2实现对象池

springboot使用commons-pool2实现对象池
参考URL: https://www.cnblogs.com/durenniu/p/12616802.html

maven引入pool2依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.2</version>
</dependency>

pool2的组成
PooledObject(池化对象) PooledObjectFactory(对象工厂) ObjectPool (对象池)

二、常用API

1. GenericObjectPool

GenericObjectPool继承BaseGenericObjectPool实现ObjectPool,通常用此实现来作为默认的连接池对象。
BaseGenericObjectPool一个抽象类,主要实现了两个功能:

注册JMX
管理一个连接池驱逐线程,此线程调用GenericObjectPool的evict()驱逐超过最大生命周期的连接对象。

ObjectPool连接池的最上层接口,定义了一个连接池必须具备的方法,比如借用一个连接对象T borrowObject(),归还一个使用后的连接对象void returnObject(T obj)。

该类代表对象池,有许多实用方法。如:

  • 从池中获取对象 borrowObject()
  • 归还对象到池中 returnObject(T obj)
  • clear() clear方法是用来清空里面处于idle状态的对象,而close方法则用来关闭整个pool。
  • close() close方法则用来关闭整个pool,close之后则连pool都访问不了了。

2. PooledObject

PooledObject是个接口DefaultPooledObject,默认实现是,PooledObject主要是对需要被加入到pool里的对象提供一个包装,方便来查看或者统计一些对象信息,比如某个对象创建的时间,空闲时间以及活跃时间等。

它有一个很重要的成员变量DefaultPooledObject枚举类,用于描述对象的状态。

public enum PooledObjectState {
    IDLE,
    ALLOCATED,
    EVICTION,
    EVICTION_RETURN_TO_HEAD,
    VALIDATION,
    VALIDATION_PREALLOCATED,
    VALIDATION_RETURN_TO_HEAD,
    INVALID,
    ABANDONED,
    RETURNING;

    private PooledObjectState() {
    }
}

3. PooledObjectFactory

PooledObjectFactory用于生成连接对象的工厂接口。该接口包含以下功能:PooledObjectFactory用于生成连接对象的工厂接口。该接口包含以下功能:

  1. 产生一个连接对象:

PooledObject makeObject() throws Exception;

在连接池初始化时初始化最小连接数
驱逐线程驱逐完过期连接后池中连接数<最小连接数,需重新生成连接,使连接数达到池中最小连接数
获取新的连接时,池中连接对象均被占用,但当前连接数<总连接数时
一般当遇到以上3中情况时需要调用该方法产生一个新的连接

  1. 销毁一个连接对象:
void destroyObject(PooledObject<T> p) throws Exception;

调用该方法销毁一个连接对象。对于实现这个方法来说非常重要的是要考虑到处理异常情况,另外实现必须考虑一个实例如果与垃圾回收器失去联系那么永远不会被销毁

  1. 校验方法
	boolean validateObject(PooledObject<T> p);

此方法主要用于校验一个连接是否可用,比如在borrow一个连接时或者return一个连接时,调用该方法检测连接是否可用。需要注意的是校验方法只会作用于激活的对象实例上。通常的做法是在连接对象空闲的时候进行校验,而不是在使用的时候进行校验,因为这样会影响性能。
4. 重新激活一个对象

void activateObject(PooledObject<T> p) throws Exception;

激活一个对象,在向对象池归还被钝化过的对象时调用该方法。
5. 钝化一个对象

void passivateObject(PooledObject<T> p) throws Exception;

钝化一个对象。在向对象池归还一个对象是会调用这个方法。

当一个对象从借用到归还需经过如下流程:
在这里插入图片描述

4. GenericObjectPoolConfig

GenericObjectPool对象池使用优化
参考URL: https://www.jianshu.com/p/397169e211de

对象池相关配置使用该类。 GenericObjectPool对象池使用优化。

三、commons-pool2 2 - poolObject API与状态机

commons-pool2 2 - poolObject API与状态机
参考URL: https://www.jianshu.com/p/6fc57ccfcee0

四、分析jedis如何使用commons pool2

jedis github:https://github.com/redis/jedis

利用commons pool2开发高性能的连接池
参考URL: https://www.jianshu.com/p/44f0156b304d
jedisPool实现原理及源码分析(1)----对象池的说明
参考URL: https://www.cnblogs.com/plf112233/p/6527902.html

Jedis实例不是线程安全的,所以不可以多个线程共用一个Jedis实例,但是创建太多的实现也不好因为这意味着会建立很多sokcet连接。
JedisPool是一个线程安全的网络连接池。可以用JedisPool创建一些可靠Jedis实例,可以从池中获取Jedis实例,使用完后再把Jedis实例还回JedisPool。这种方式可以避免创建大量socket连接并且会实现高效的性能.。

我们分析一下JedisPool 版本3.1.0是如何使用的:
在这里插入图片描述如上图,核心类主要有个三个其自定义类JedisPool继承GenericObjectPool、JedisFactory继承PooledObjectFactory、JedisPoolConfig继承GenericObjectPoolConfig。

1. JedisPool继承Pool封装成员变量GenericObjectPool

JedisPool用于管理要被池化的对象的借出和归还,并通知PoolableObjectFactory完成相应的工作;

它定义了一个JedisPool类 继承 Pool
如下,这个抽象类Pool 很重要,它内部封装了GenericObjectPool成员变量

public abstract class Pool<T> implements Closeable {
  protected GenericObjectPool<T> internalPool;

JedisPool的构造函数中,创建了GenericObjectPool成员变量,传入new GenericObjectPoolConfig()作为对象池参数。

  public JedisPool(final String host) {
    URI uri = URI.create(host);
    if (JedisURIHelper.isValid(uri)) {
      this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(uri,
          Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null), new GenericObjectPoolConfig());
    } else {
      this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host,
          Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null,
          Protocol.DEFAULT_DATABASE, null), new GenericObjectPoolConfig());
    }
  }

其中内部封装的 GenericObjectPool 非常核心,代表对象池。

public JedisPool(GenericObjectPoolConfig poolConfig, String host) {
this(poolConfig, (String)host, 6379);
}

对外暴露的接口
getResource //从连接池中获取Jedis,会调用JedisFactory.borrowObject()
returnBrokenResource //归还不可用的Jedis对象
returnResource //归还Jedis对象,会调用returnObject(),使用完之后一定要归还,否则会导致严重的后果

2. JedisPoolConfig继承GenericObjectPoolConfig

从源码角度看JedisPoolConfig参数配置
参考URL: https://www.cnblogs.com/aflyun/p/11708003.html
jedis连接池配置详解jedisPoolConfig
参考URL: https://www.cnblogs.com/forward22222/p/9601820.html

JedisPoolConfig的配置参数
(1)maxTotal:默认值8:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制。

(2)maxIdle:默认值8:最大能够保持idle的数量,控制一个pool最多有多少个状态为idle的jedis实例。

(3)minIdle:默认值0:资源池确保的最少空闲连接数。

(4)blockWhenExhausted:默认值true:当资源池用尽后,调用者是否要等待。只有当值为true时,下面的maxWaitMillis才会生效。建议使用默认值。

(5)maxWaitMillis:当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)。 不建议使用默认值。

(6)testOnBorrow:默认值false:获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;业务量很大时候建议设置为false,减少一次ping的开销。
注意:这个设置为true,它的test检测机制: 是pool调用borrowObject()时,borrowObject方法内部调你的自定义的factory继承PooledObjectFactory覆写的 validateObject()方法。总结:设置为true时,就是在池中取资源对象时,会调用你自己覆写的 validateObject 方法验证该资源对象是否可用。validateObject 会放回true or false。 true校验通过,false校验不通过。对于校验不通过的borrowObject内部逻辑会调destroy销毁该对象。

(7)testOnReturn:默认值false:向资源池归还连接时是否做连接有效性检测(ping)。检测到无效连接将会被移除。业务量很大时候建议设置为false,减少一次ping的开销。

空闲Jedis对象检测由下列四个参数组合完成,testWhileIdle是该功能的开关:
(1)testWhileIdle:默认值false:是否开启空闲资源检测。如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;建议设置为true。

(2)timeBetweenEvictionRunsMillis:默认值-1(不检测) :空闲资源的检测周期(单位为毫秒)。表示idle object evitor两次扫描之间要sleep的毫秒数; 建议设置,周期自行选择。

(3)minEvictableIdleTimeMillis:默认值180000(即30分钟):资源池中资源的最小空闲时间(单位为毫秒),达到此值后空闲资源将被移除。表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;
总结:就是说一个资源对象归还后,多久

(4)numTestsPerEvictionRun:默认值 3:做空闲资源检测时,每次检测资源的个数。可根据自身应用连接数进行微调,如果设置为 -1,就是对所有连接做空闲监测。

说明 可以在org.apache.commons.pool2.impl.BaseObjectPoolConfig中查看全部默认值。

3. JedisFactory 实现PooledObjectFactory

JedisFactory 实现PooledObjectFactory ,所有对象的创建销毁、激活和有效性验证都在JedisFactory工厂类中进行,

它需要复写几个方法:

  • makeObject创建池话对象
  @Override
  public PooledObject<Jedis> makeObject() throws Exception {
  • destroyObject
  @Override
  public void destroyObject(PooledObject<Jedis> pooledJedis) throws Exception {
  • validateObject
  @Override
  public boolean validateObject(PooledObject<Jedis> pooledJedis) {
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值