1. 程式人生 > >物件池commons-pool2的原理與應用

物件池commons-pool2的原理與應用

依賴必不可少

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

建立連線池物件

建立一個連線池物件的構造方法需要兩個核心類,GenericObjectPoolConfig類和PooledObjectFactory介面的實現,前者用於存放物件池的配置資訊,後者用於管理存在物件池中的“池化物件”。

1)MyPoolConfig.java,其中一些常用的屬性已經添加了註釋

public class MyPoolConfig extends GenericObjectPoolConfig {
    public MyPoolConfig(){
        setLifo(true); //池用佇列儲存物件,true表示fifo,false表示filo,預設true
        setFairness(true); //是否使用公平鎖,預設true
        setMaxWaitMillis(-1);//設定獲取空閒物件的最長等待時間,<0則一直等待,>0則等待一段時間後丟擲NoSuchElementException異常,預設值-1
        setMinEvictableIdleTimeMillis(60000); //空閒物件在redis裡超過這個時間就會被移除,預設30分鐘
        setTestOnCreate(false);//在建立物件時檢測物件是否有效,true是,預設值是false。
        setTestOnBorrow(false); //在從物件池獲取物件時是否檢測物件有效,true是;預設值是false。
        setTestOnReturn(false); //在向物件池中歸還物件時是否檢測物件有效,true是,預設值是false。
        setTestWhileIdle(true); //在檢測空閒物件執行緒檢測到物件不需要移除時,是否檢測物件的有效性。true是,預設值是false。
        setTimeBetweenEvictionRunsMillis(30000); //每隔多長時間執行一次物件空閒檢測執行緒
        setBlockWhenExhausted(true); //當物件池沒有空閒物件時,獲取物件的操作是否會被阻塞,預設true
        setMaxIdle(8);  //物件池中最大物件空閒個數
        setMaxTotal(8); //物件池中最大物件管理個數
        setMinIdle(0); //物件池中最小物件空閒個數
    }
}

2)MyPooledObjectFactory.java 由於pooledObjectFactory用於管理池化的物件,需要怎麼管理都是我們自己定的,所以我們需要自己實現一個池化物件管理factory,MyPooledObjectFactory。

import com.liantong.entity.Zhang;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 用於我們自己管理池化物件
 */
public class MysPooledObjectFactory implements PooledObjectFactory {
    private Logger logger = LoggerFactory.getLogger(MyJedisPooledObjectFactory.class);
    /**
     * 這個方法是用來建立一個物件
     * 當在GenericObjectPool類中呼叫borrowObject方法時,如果當前物件池中沒有空閒的物件,GenericObjectPool會呼叫這個方法,
     * 建立一個物件,並把這個物件封裝到PooledObject類中,並交給物件池管理。
     */
    @Override
    public PooledObject makeObject() throws Exception {
        System.out.println("make object....");
        Zhang zhang = new Zhang("110");
        DefaultPooledObject<Zhang> zhangDefaultPooledObject = new DefaultPooledObject<>(zhang);
        return zhangDefaultPooledObject;
    }

    /**
     * 銷燬物件
     * 當物件池檢測到某個物件的空閒時間(idle)超時,或使用完物件歸還到物件池之前被檢測到物件已經無效時,
     * 就會呼叫這個方法銷燬物件。物件的銷燬一般和業務相關,但必須明確的是,當呼叫這個方法之後,物件的生命週期必須結果。
     * 如果是物件是執行緒,執行緒必須已結束,如果是socket,socket必須已close,如果是檔案操作,檔案資料必須已flush,且檔案正常關閉。
     */
    @Override
    public void destroyObject(PooledObject p) throws Exception {
        System.out.println("destroy object....");
        Object object = p.getObject();
        object = null;
    }

    /**
     * 檢測一個物件是否有效
     * 在物件池中的物件必須是有效的,這個有效的概念是,從物件池中拿出的物件是可用的。
     * 比如,如果是socket,那麼必須保證socket是連線可用的。
     * 在從物件池獲取物件或歸還物件到物件池時,會呼叫這個方法,判斷物件是否有效,如果無效就會銷燬。
     */
    @Override
    public boolean validateObject(PooledObject p) {
        System.out.println("validate object");
        if (p.getObject()==null) {
            return false;
        }else{
            return true;
        }
    }

    /**
     * 啟用一個物件或者說啟動物件的某些操作
     * 比如,如果物件是socket,如果socket沒有連線,或意外斷開了,可以在這裡啟動socket的連線。
     * 它會在檢測空閒物件的時候,如果設定了測試空閒物件是否可以用testwhileidle,就會呼叫這個方法,在borrowObject的時候也會呼叫。
     * 另外,如果物件是一個包含引數的物件,可以在這裡進行初始化。讓使用者感覺這是一個新建立的物件一樣。
     */
    @Override
    public void activateObject(PooledObject p) throws Exception {
        System.out.println("activate object");
    }

    /**
     * 鈍化一個物件。在向物件池歸還一個物件是會呼叫這個方法。這裡可以對物件做一些清理操作。
     * 比如清理掉過期的資料,下次獲得物件時,不受舊資料的影響。
     */
    @Override
    public void passivateObject(PooledObject p) throws Exception {
        System.out.println("passivte object");
    }
}

建立需要被池化的物件

public class Zhang {
    private String accNbr;
    public Zhang(String accNbr){
        this.accNbr = accNbr;
    }
    public String getAccNbr() {
        return accNbr;
    }
    public void setAccNbr(String accNbr) {
        this.accNbr = accNbr == null ? null : accNbr.trim();
    }
}

編寫測試類

public class TestClass {
    @Test
    public void testRedisA() {
        MyPooledObjectFactory myJedisPooledObjectFactory = new MyPooledObjectFactory();
        MyPoolConfig myJedisPoolConfig = new MyPoolConfig();
        GenericObjectPool<Zhang> genericObjectPool = new GenericObjectPool<Zhang>(myPooledObjectFactory,myPoolConfig);
        try {
            for(int i=0; i<3; i++) {
                Thread.sleep(1000);
                //獲取資源物件
                Zhang user = genericObjectPool.borrowObject();
                //將獲取的資源物件,返還給資源池
                genericObjectPool.returnObject(user);
                //輸出資源物件
                System.out.println(JSON.toJSONString(user));
                System.out.println();
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

輸出結果為

make object....
activate object
passivte object
{"accNbr":"110"}

activate object
passivte object
{"accNbr":"110"}

activate object
passivte object
{"accNbr":"110"}