小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Apache common-pool, common-dbcp源碼解讀與對(duì)象池原理剖析 -...

 goldbomb 2009-01-22
最近在做一個(gè)內(nèi)部測(cè)試工具類的優(yōu)化工作中接觸到了連接池, 對(duì)象池技術(shù), 將原有的未使用連接池的數(shù)據(jù)庫訪問操作改成連接池方式.性能有了非常大的提升, 事實(shí)證明, 經(jīng)過兩次改造, 原來一個(gè)比較大的測(cè)試類需要500多秒, 第一次優(yōu)化后只需要300多秒, 第二次改用連接池之后同一個(gè)測(cè)試類只需要80多秒.下面是改造過程中的一些總結(jié).
對(duì)象池就是以"空間換時(shí)間"的一種常用緩存機(jī)制, 這里的"時(shí)間"特指創(chuàng)建時(shí)間,因此這也給出了對(duì)象池的適用范圍:如果一種對(duì)象的創(chuàng)建過程非常耗時(shí)的話, 那么請(qǐng)使用對(duì)象池. 內(nèi)部原理簡單的說, 就是將創(chuàng)建的對(duì)象放到一個(gè)容器中, 用完之后不是銷毀而是再放回該容器, 讓其他的對(duì)象調(diào)用, 對(duì)象池中還涉及到一些高級(jí)的技術(shù), 比如過期銷毀, 被破壞時(shí)銷毀, 對(duì)象數(shù)超過池大小銷毀, 對(duì)象池中沒有可用空閑對(duì)象時(shí)等待等等.

apache的common-pool工具庫是對(duì)池化技術(shù)原理的一種具體實(shí)現(xiàn). 在闡述原來之前, 這里先理解幾個(gè)概念:
對(duì)象池(ObjectPool接口): 可以把它認(rèn)為是一種容器, 它是用來裝池對(duì)象的, 并且包含了用來創(chuàng)建池對(duì)象的工廠對(duì)象
池對(duì)象:就是要放到池容器中的對(duì)象, 理論上可以是任何對(duì)象.
對(duì)象池工廠(ObjectPoolFactory接口):用來創(chuàng)建對(duì)象池的工廠, 這個(gè)沒什么好說的.
池對(duì)象工廠(PoolableObjectFactory接口):用來創(chuàng)建池對(duì)象, 將不用的池對(duì)象進(jìn)行鈍化(passivateObject), 對(duì)要使用的池對(duì)象進(jìn)行激活(activeObject), 對(duì)池對(duì)象進(jìn)行驗(yàn)證(validateObject), 對(duì)有問題的池對(duì)象進(jìn)行銷毀(destroyObject)等工作

對(duì)象池中封裝了創(chuàng)建, 獲取, 歸還, 銷毀池對(duì)象的職責(zé), 當(dāng)然這些工作都是通過池對(duì)象工廠來實(shí)施的, 容器內(nèi)部還有一個(gè)或多個(gè)用來盛池對(duì)象的容器.對(duì)象池會(huì)對(duì)容器大小, 存放時(shí)間, 訪問等待時(shí)間, 空閑時(shí)間等等進(jìn)行一些控制, 因?yàn)榭梢愿鶕?jù)需要來調(diào)整這些設(shè)置.

當(dāng)需要拿一個(gè)池對(duì)象的時(shí)候, 就從容器中取出一個(gè), 如果容器中沒有的話, 而且又沒有達(dá)到容器的最大限制, 那么就調(diào)用池對(duì)象工廠, 新建一個(gè)池對(duì)象, 并調(diào)用工廠的激活方法, 對(duì)創(chuàng)建的對(duì)象進(jìn)行激活, 驗(yàn)證等一系列操作. 如果已經(jīng)達(dá)到池容器的最大值, 而對(duì)象池中又經(jīng)沒有空閑的對(duì)象, 那么將會(huì)繼續(xù)等待, 直到有新的空閑的對(duì)象被丟進(jìn)來, 當(dāng)然這個(gè)等待也是有限度的, 如果超出了這個(gè)限度, 對(duì)象池就會(huì)拋出異常.

"出來混, 總是要還的", 池對(duì)象也是如此, 當(dāng)將用完的池對(duì)象歸還到對(duì)象池中的時(shí)候, 對(duì)象池會(huì)調(diào)用池對(duì)象工廠對(duì)該池對(duì)象進(jìn)行驗(yàn)證, 如果驗(yàn)證不通過則被認(rèn)為是有問題的對(duì)象, 將會(huì)被銷毀, 同樣如果容器已經(jīng)滿了, 這個(gè)歸還池對(duì)象將變的"無家可歸", 也會(huì)被銷毀, 如果不屬于上面兩種情況, 對(duì)象池就會(huì)調(diào)用工廠對(duì)象將其鈍化并放入容器中. 在整個(gè)過程中, 激活, 檢查, 鈍化處理都不是必須的, 因此我們?cè)趯?shí)現(xiàn)PoolableObjectFactory接口的時(shí)候, 一般不作處理, 給空實(shí)現(xiàn)即可, 所以誕生了BasePoolableObjectFactory.

當(dāng)然你也可以將要已有的對(duì)象創(chuàng)建好, 然后通過addObject放到對(duì)象池中去, 以備后用.

為了確保對(duì)對(duì)象池的訪問都是線程安全的, 所有對(duì)容器的操作都必須放在synchronized中.

在apache的common-pool工具庫中有5種對(duì)象池:GenericObjectPool和GenericKeyedObjectPool, SoftReferenceObjectPool, StackObjectPool, StackKeyedObjectPool.
五種對(duì)象池可分為兩類, 一類是無key的:

另一類是有key的:

前面兩種用CursorableLinkedList來做容器, SoftReferenceObjectPool用ArrayList做容器, 一次性創(chuàng)建所有池化對(duì)象, 并對(duì)容器中的對(duì)象進(jìn)行了軟引用(SoftReference)處理, 從而保證在內(nèi)存充足的時(shí)候池對(duì)象不會(huì)輕易被jvm垃圾回收, 從而具有很強(qiáng)的緩存能力. 最后兩種用Stack做容器. 不帶key的對(duì)象池是對(duì)前面池技術(shù)原理的一種簡單實(shí)現(xiàn), 帶key的相對(duì)復(fù)雜一些, 它會(huì)將池對(duì)象按照key來進(jìn)行分類, 具有相同的key被劃分到一組類別中, 因此有多少個(gè)key, 就會(huì)有多少個(gè)容器. 之所以需要帶key的這種對(duì)象池, 是因?yàn)槠胀ǖ膶?duì)象池通過makeObject()方法創(chuàng)建的對(duì)象基本上都是一模一樣的, 因?yàn)闆]法傳遞參數(shù)來對(duì)池對(duì)象進(jìn)行定制. 因此四種池對(duì)象的區(qū)別主要體現(xiàn)在內(nèi)部的容器的區(qū)別, Stack遵循"后進(jìn)先出"的原則并能保證線程安全, CursorableLinkedList是一個(gè)內(nèi)部用游標(biāo)(cursor)來定位當(dāng)前元素的雙向鏈表, 是非線程安全的, 但是能滿足對(duì)容器的并發(fā)修改.ArrayList是非線程安全的, 便利方便的容器.

使用對(duì)象池的一般步驟:創(chuàng)建一個(gè)池對(duì)象工廠, 將該工廠注入到對(duì)象池中, 當(dāng)要取池對(duì)象, 調(diào)用borrowObject, 當(dāng)要?dú)w還池對(duì)象時(shí), 調(diào)用returnObject, 銷毀池對(duì)象調(diào)用clear(), 如果要連池對(duì)象工廠也一起銷毀, 則調(diào)用close().
下面是一些時(shí)序圖:
borrowObject:

returnObject:

invalidateObject:


apache的連接池工具庫common-dbcp是common-pool在數(shù)據(jù)庫訪問方面的一個(gè)具體應(yīng)用.當(dāng)對(duì)common-pool熟悉之后, 對(duì)common-dbcp就很好理解了. 它通過對(duì)已有的Connection, Statment對(duì)象包裝成池對(duì)象PoolableConnection, PoolablePreparedStatement. 然后在這些池化的對(duì)象中, 持有一個(gè)對(duì)對(duì)象池的引用, 在關(guān)閉的時(shí)候, 不進(jìn)行真正的關(guān)閉處理, 而是通過調(diào)用:
Java代碼 復(fù)制代碼
  1. _pool.returnObject(this);  

或:
Java代碼 復(fù)制代碼
  1. _pool.returnObject(_key,this);  

這樣一句, 將連接對(duì)象放回連接池中.
而對(duì)應(yīng)的對(duì)象池前者采用的是ObjectPool, 后者是KeyedObjectPool, 因?yàn)橐粋€(gè)數(shù)據(jù)庫只對(duì)應(yīng)一個(gè)連接, 而執(zhí)行操作的Statement卻根據(jù)Sql的不同會(huì)分很多種. 因此需要根據(jù)sql語句的不同多次進(jìn)行緩存
在對(duì)連接池的管理上, common-dbcp主要采用兩種對(duì)象:
一個(gè)是PoolingDriver, 另一個(gè)是PoolingDataSource, 二者的區(qū)別是PoolingDriver是一個(gè)更底層的操作類, 它持有一個(gè)連接池映射列表, 一般針對(duì)在一個(gè)jvm中要連接多個(gè)數(shù)據(jù)庫, 而后者相對(duì)簡單一些. 內(nèi)部只能持有一個(gè)連接池, 即一個(gè)數(shù)據(jù)源對(duì)應(yīng)一個(gè)連接池.
下面是common-dbcp的結(jié)構(gòu)關(guān)系:


下面是參考了common-dbcp的例子之后寫的一個(gè)從連接池中獲取連接的工具類
Java代碼 復(fù)制代碼
  1. /**  
  2.  * 創(chuàng)建連接  
  3.  *   
  4.  * @since 2009-1-22 下午02:58:35  
  5.  */  
  6. public class ConnectionUtils {   
  7.     // 一些common-dbcp內(nèi)部定義的protocol   
  8.     private static final String POOL_DRIVER_KEY = "jdbc:apache:commons:dbcp:";   
  9.     private static final String POLLING_DRIVER = "org.apache.commons.dbcp.PoolingDriver";   
  10.   
  11.     /**  
  12.      * 取得池化驅(qū)動(dòng)器  
  13.      *   
  14.      * @return  
  15.      * @throws ClassNotFoundException  
  16.      * @throws SQLException  
  17.      */  
  18.     private static PoolingDriver getPoolDriver() throws ClassNotFoundException,   
  19.             SQLException {   
  20.         Class.forName(POLLING_DRIVER);   
  21.         return (PoolingDriver) DriverManager.getDriver(POOL_DRIVER_KEY);   
  22.     }   
  23.   
  24.     /**  
  25.      * 銷毀所有連接  
  26.      *   
  27.      * @throws Exception  
  28.      */  
  29.     public static void destory() throws Exception {   
  30.         PoolingDriver driver = getPoolDriver();   
  31.         String[] names = driver.getPoolNames();   
  32.         for (String name : names) {   
  33.             driver.getConnectionPool(name).close();   
  34.         }   
  35.     }   
  36.   
  37.     /**  
  38.      * 從連接池中獲取數(shù)據(jù)庫連接  
  39.      */  
  40.     public static Connection getConnection(TableMetaData table)   
  41.             throws Exception {   
  42.         String key = table.getConnectionKey();   
  43.   
  44.         PoolingDriver driver = getPoolDriver();   
  45.   
  46.         ObjectPool pool = null;   
  47.         // 這里找不到連接池會(huì)拋異常, 需要catch一下   
  48.         try {   
  49.             pool = driver.getConnectionPool(key);   
  50.         } catch (Exception e) {   
  51.         }   
  52.            
  53.         if (pool == null) {   
  54.             // 根據(jù)數(shù)據(jù)庫類型構(gòu)建連接工廠   
  55.             ConnectionFactory connectionFactory = null;   
  56.             if (table.getDbAddr() != null  
  57.                     && TableMetaData.DB_TYPE_MYSQL == table.getDbType()) {   
  58.                 Class.forName(TableMetaData.MYSQL_DRIVER);   
  59.                 connectionFactory = new DriverManagerConnectionFactory(table   
  60.                         .getDBUrl(), null);   
  61.             } else {   
  62.                 Class.forName(TableMetaData.ORACLE_DRIVER);   
  63.                 connectionFactory = new DriverManagerConnectionFactory(table   
  64.                         .getDBUrl(), table.getDbuser(), table.getDbpass());   
  65.             }   
  66.                
  67.             // 構(gòu)造連接池   
  68.             ObjectPool connectionPool = new GenericObjectPool(null);   
  69.             new PoolableConnectionFactory(connectionFactory, connectionPool,   
  70.                     nullnullfalsetrue);   
  71.                
  72.             // 將連接池注冊(cè)到driver中   
  73.             driver.registerPool(key, connectionPool);   
  74.         }   
  75.   
  76.         // 從連接池中拿一個(gè)連接   
  77.         return DriverManager.getConnection(POOL_DRIVER_KEY + key);   
  78.     }   
  79.   
  80. }  


雖然對(duì)象池技術(shù)在實(shí)際開發(fā)過程中用的不是很多, 但是理解之后對(duì)我們寫程序還是有莫大的好處的, 至少我是這樣的

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多