1. 程式人生 > >物件池commons-pool框架的研究以及原始碼分析(一)

物件池commons-pool框架的研究以及原始碼分析(一)

    物件池是一個物件集合,用於將建立好的物件存在該集合中,當需要使用池中的物件時,再從池中取出,恰當地使用物件池可以有效減少物件生成和初始化時的消耗,提高系統的執行效率。另外,利用物件池還可以對物件的狀態做一定的維護,確保物件是可用的,提高程式的健壯性。注意:物件池技術,在用於一些建立需要佔用大量時間上的物件特別明顯,在一些小物件處理上,效能不一定有優勢。

Common Pool元件提供了一整套實現物件池化的框架,而且是執行緒安全的,我們可以不用自己花大量的精力編寫程式碼就可以使用物件池對物件的管理。抱著先使用再分析,最後研究原始碼的原則,我們先看第一個例子:

首先建立一個簡單的User類,用於生成物件:

public class User
{
private int id;
private String userName;

 
public User(int id, String userName) {
super();
this.id = id;
this.userName = userName;
}
public User( ) {
 
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String toString(){
return "user id is:"+id+",userName:"+userName;
}
}

核心程式碼來了,建立一個物件狀態管理工廠,用於對物件狀態的維護:

/**
* 這個類主要負責對我們的物件進行管理,由我們自己建立、啟用等
* 實際使用中,我們將這個類傳遞給物件池,由物件池呼叫我們自己編寫的程式碼進行管理
* @author Administrator
*
*/
public class UserFactory implements PoolableObjectFactory{
//啟用物件
public void activateObject(Object obj) throws Exception {
// TODO Auto-generated method stub
System.out.println("activateObject");
}
/**
* 銷燬物件,注意呼叫了這個方法之後,物件被銷燬,但物件池還有這個物件
*/
public void destroyObject(Object obj) throws Exception {
  System.out.println("destroyObject" );  
        //對物件進行銷燬,我們暫時將物件設定為NULL
  obj = null;
 //如果是資料庫的連線池,可以將conn設定為close

}
/**
* 建立物件
*/
public Object makeObject() throws Exception {
// TODO Auto-generated method stub
return new User();
}
/**
* 歸還物件後呼叫的方法
*/
public void passivateObject(Object obj) throws Exception {
  System.out.println("物件已經被歸還" );  
  //如果是資料庫連線池,可以設定為提交連線

}
/**
* 驗證物件使用可用
*/
public boolean validateObject(Object obj) {
//我們這個簡單的user類好像作用不大,但如果是資料庫連線池,可以讓其執行SELECT 1 來驗證資料庫連線是否可用
 System.out.println("驗證一下物件是否可用" );  
return true;
}

}

//再編寫一個方法,來測試使用連線池情況

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
UserFactory userFactory = new commonPool().new UserFactory();//內部類的例項化方法,程式碼的可讀性不強
ObjectPool objectPool = new StackObjectPool(userFactory);
User user = (User)objectPool.borrowObject();
user.setId(1);
user.setUserName("testnam3");
System.out.println(user);
objectPool.returnObject(user);
//-----------------------------歸還後再借物件
User user2 = (User)objectPool.borrowObject();
System.out.println(user2);

}

從程式碼中可以看出,首先建立一個物件維護工廠UserFactory來維護物件的狀態,這種做法在設計上非常值得學習,對物件的維護,仍然由我們自己編寫程式碼維護,因為物件的複雜性,由我們自己將維護的程式碼傳遞給物件池,由物件池呼叫我們的物件維護例項對物件進行維護,在設計上相當精妙,今後我們在軟體開發中,需要學習它這種設計方式。

建立完物件維護工廠後,就可以建立一個物件池,然後呼叫物件池的方法獲取物件或歸還物件,從程式碼中可以看出,ObjectPool 是一個介面,我們來看看這個介面包括了哪些方法:

 Object borrowObject() throws Exception;//從物件池中獲取物件
    void returnObject(Object obj) throws Exception;//將物件還給物件池
    void invalidateObject(Object obj) throws Exception;//將物件設定為無效
    void addObject() throws Exception;//新增物件
    int getNumIdle() throws UnsupportedOperationException;//獲取空閒物件數目
    int getNumActive() throws UnsupportedOperationException;//獲取正在使用的物件數目
    void clear() throws Exception, UnsupportedOperationException;//清除空閒物件
    void close() throws Exception;//關閉物件池並釋放物件資源
    void setFactory(PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException;//設定物件狀態維護工廠

實際上,與我們接觸最多的兩個介面,就是物件狀態維護工廠以及物件池介面,下面我們再看看程式碼執行結果:

activateObject
驗證一下物件是否可用
user id is:1,userName:testnam3
驗證一下物件是否可用
物件已經被歸還
activateObject
驗證一下物件是否可用
user id is:1,userName:testnam3

從結果我們可以看出,物件歸還後,並沒有銷燬掉,而是存放在池中,當我們重新獲取物件時,又從池中取出。另外,物件池呼叫在借用物件、歸還物件時,物件池自動呼叫了物件驗證的方法,是否需要驗證,可以通過配置來實現,後面程式碼中再具體分析。

特別提出:使用物件池時,借用物件,必須歸還,所謂有借有還,下次再借不難,上面的演示程式碼,最後一次借用物件後沒有歸還,在實際應用中,這種做法是不可取的。