commons-pool2自定義對象池-快速開始

一、什麼是commons-pool2

利用commons-pool2自定義對象池

commons-pool2是Apache下一個開源的公共資源池。我們可以根據它來快速的建立一個自己的對象池。

  • 鏈接池/對象池(ObjectPool):用於存放鏈接對象的一個池子(集合),通常用數組或者List對象.durid用兩個數組分別保存活躍的鏈接和空閒鏈接.commons-pool2用雙端阻塞隊列LinkedBlockingDeque保存空閒鏈接
    用ConcurrentHashMap保存所有的鏈接.

  • 對象工廠(PooledObjectFactory):連接池工廠,用於產生一個新的鏈接對象.

  • 鏈接對象/池中對象(PooledObject):鏈接池裏面存放的對象.

核心類:

  1. PooledObjectFactory【對象工廠】,用於產生一個新對象。
  2. ObjectPool【鏈接池】,用於存放鏈接對象的一個池子,提供接口用於對象的借取和歸還。
  3. PooledObject【鏈接對象】,鏈接池內的對象。

二、常用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

利用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) {

五、thrift連接池的實現

Thrift RPC實戰(四) thrift連接池的實現
參考URL: https://www.jianshu.com/p/269568b7bf5b

發佈了87 篇原創文章 · 獲贊 36 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章