一、概述
Apache Commons Pool庫提供了一整套用於實現對象池化的API,以及若干種各具特色的對象池實現。2.0版本,並非是對1.x的簡單升級,而是一個完全重寫的對象池的實現,顯著的提升了性能和可伸縮性,並且包含可靠的實例跟蹤和池監控。第二版要求JDK1.6+。
二、下載
官方下載頁:
http://commons.apache.org/proper/commons-pool/download_pool.cgi
源碼:
svn checkout http://svn.apache.org/repos/asf/commons/proper/pool/trunk commons-pool2
Maven工程依賴
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.0</version>
</dependency>
三、使用說明
3.1 創建池化對象
創建池化對象很簡單,只要實現commons-pool的PooledObjectFactory工廠接口就行了。
PooledObjectFactory是一個池化對象工廠接口,定義了生成對象、激活對象、鈍化對象、銷毀對象的方法,如下:
public interface PooledObjectFactory<T> {
PooledObject<T> makeObject();
void activateObject(PooledObject<T> obj);
void passivateObject(PooledObject<T> obj);
boolean validateObject(PooledObject<T> obj);
void destroyObject(PooledObject<T> obj);
}
它創建並管理PooledObject。PooledObject包含了池化的對象實例,以及這些實例的池化屬性,比如創建時間、最后使用時間等等。
如果需要使用Commons-Pool,那么你就需要提供一個PooledObjectFactory接口的具體實現。一個比較簡單的辦法就是,繼承BasePooledObjectFactory這個抽象類。而繼承這個抽象類,只需要實現兩個方法:create()和wrap(T obj)。
實現create()方法很簡單,而實現wrap(T obj)也有捷徑,可以使用類DefaultPooledObject ,代碼可以參考如下:
@Override
public PooledObject<Foo> wrap(Foo foo) {
return new DefaultPooledObject<Foo>(foo);
}
比如,一個完整的例子:
package test.test;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
public class StringBufferFactory extends BasePooledObjectFactory<StringBuffer> {
@Override
public StringBuffer create() throws Exception {
return new StringBuffer();
}
@Override
public PooledObject<StringBuffer> wrap(StringBuffer obj) {
return new DefaultPooledObject<StringBuffer>(obj);
}
}
有時候,單用對池內所有對象一視同仁的對象池,並不能解決問題。例如,有時需要通過key來獲取不同的對象,這樣,就有可能取出不合用的對象的麻煩。當然,可以通過為每一組參數相同的同類對象建立一個單獨的對象池來解決這個問題。但是,如果使用普通的ObjectPool來實施這個計策的話,因為普通的PooledObjectFactory只能生產出大批設置完全一致的對象,就需要為每一組參數相同的對象編寫一個單獨的PooledObjectFactory,工作量相當可觀。這種時候就可以使用BaseKeyedPooledObjectFactory來替代BasePooledObjectFactory.這個類,實現的是KeyedPooledObjectFactory接口,和PooledObjectFactory接口類似,只是在相關的方法中多了Key參數,定義如下:
public interface KeyedPoolableObjectFactory<K,V> {
PooledObject<V> makeObject(K key);
void activateObject(K key, PooledObject<V> obj);
void passivateObject(K key, PooledObject<V> obj);
boolean validateObject(K key, PooledObject<V> obj);
void destroyObject(K key, PooledObject<V> obj);
}
3.2 創建對象池
在org.apache.commons.pool2.impl中預設了三個可以直接使用的對象池:GenericObjectPool、GenericKeyedObjectPool和SoftReferenceObjectPool。
通常使用GenericObjectPool來創建對象池,如果是對象池是Keyed的,那么可以使用GenericKeyedObjectPool來創建對象池。這兩個類都提供了豐富的配置選項。這兩個對象池的特點是可以設置對象池中的對象特征,包括LIFO方式、最大空閑數、最小空閑數、是否有效性檢查等等。兩者的區別如前面所述,后者支持Keyed。
而SoftReferenceObjectPool對象池,它利用一個java.util.ArrayList對象來保存對象池里的對象。不過它並不在對象池里直接保存對象本身,而是保存它們的“軟引用”(Soft Reference)。這種對象池的特色是:可以保存任意多個對象,不會有容量已滿的情況發生;在對象池已空的時候,調用它的borrowObject方法,會自動返回新創建的實例;可以在初始化同時,在池內預先創建一定量的對象;當內存不足的時候,池中的對象可以被Java虛擬機回收。
舉個例子:
new GenericObjectPool<StringBuffer>(new StringBufferFactory());
我們也可以使用GenericObjectPoolConfig來對上面創建的對象池進行一些參數配置,創建的Config參數,可以使用setConfig方法傳給對象池,也可以在對象池的構造方法中作為參數傳入。
舉個例子:
GenericObjectPoolConfig conf = new GenericObjectPoolConfig();
conf.setMaxTotal(20);
conf.setMaxIdle(10);
...
GenericObjectPool<StringBuffer> pool = new GenericObjectPool<StringBuffer>(new StringBufferFactory(), conf);
3.3 使用對象池
對象池使用起來很方便,簡單一點就是使用borrowObject和returnObject兩個方法,直接給參考代碼吧:
StringBuffer buf = null;
try {
buf = pool.borrowObject();
...
} catch(IOException e) {
throw e;
} catch(Exception e) {
throw new RuntimeException("Unable to borrow buffer from pool" +
e.toString());
} finally {
try {
if(null != buf) {
pool.returnObject(buf);
}
} catch(Exception e) {
// ignored
}
}
