JAVA自定義連接池原理設計(一)


一,概述

本人認為在開發過程中,需要挑戰更高的階段和更優的代碼,雖然在真正開發工作中,代碼質量和按時交付項目功能相比總是無足輕重。但是個人認為開發是一條任重而道遠的路。現在本人在網上找到一個自定義連接池的代碼,分享給大家。無論是線程池還是db連接池,他們都有一個共同的特征:資源復用,在普通的場景中,我們使用一個連接,它的生命周期可能是這樣的:

 

一個連接,從創建完畢到銷毀,期間只被使用一次,當周期結束之后,另外的調用者仍然需要這個連接去做事,就要重復去經歷這種生命周期。因為創建和銷毀都是需要對應服務消耗時間以及系統資源去處理的,這樣不僅浪費了大量的系統資源,而且導致業務響應過程中都要花費部分時間去重復的創建和銷毀,得不償失,而連接池便被賦予了解決這種問題的使命!

二,連接池簡要需求

和原始周期相比,連接池多了一下特性:

1,創建並不是真的創建,而是從池子中選出空閑連接。

2,銷毀並不是真的銷毀,而是將使用中的連接放回池中。

3,真正的創建和銷毀由線程池的特性機制來決定。

4,保存連接的容器是必不可少的,另外,該容器也要支持連接的添加和移除功能,並保證線程安全。

5,我們需要因為要對連接的銷毀做邏輯調整,我們需要重寫它的close以及isClosed方法。

6,我們需要有個入口對連接池做管理,例如回收空閑連接,連接池不僅僅只是對Connection生命周期的控制,還應該加入一些特色,例如初始連接數,最大連接數,最小連接數、最大空閑時長以及獲取連接的等待時長,這些我們也簡單支持一下。

容器連接池的選型:

1,要保證線程安全,我們可以將目標瞄准在JUC包下的神通們,設我們想要的容器為X,那么X不僅需要滿足基本的增刪改查功能,而且也要提供獲取超時功能,這是為了保證當池內長時間沒有空閑連接時不會導致業務阻塞,即刻熔斷。另外,x需要滿足雙向操作,這是為了連接池可以識別出飽和的空閑連接,方便回收操作。

綜上所述,LinkedBlockingDeque是最合適的選擇,它使用InterruptibleReentrantLock來保證線程安全,使用Condition來做獲取元素的阻塞,另外支持雙向操作。

另外,我們可以將連接池分為3個類型:

工作池:存在正在被使用的連接。

空閑池:存在空閑連接。

回收池:已經被回收(物理關閉)的連接。

其中,工作池和回收池大可不必用雙向隊列,或許用單向隊列或者set都可以代替之:

 

private LinkedBlockingQueue<HoneycombConnection> workQueue;
private LinkedBlockingQueue<HoneycombConnection> idleQueue;
private LinkedBlockingQueue<HoneycombConnection> freezeQueue;

 

 

 

 

Connection 的裝飾

連接池的輸出是Connection,它代表着一個db連接,上游服務使用它做完操作后,會直接調用它的close方法來釋放連接,而我們必須做的是在調用者無感知的情況下改變它的關閉邏輯,當調用close的方法時,我們將它放回空閑隊列中,保證其的可復用性!

因此,我們需要對原來的Connection做裝飾,其做法很簡單,但是很累,這里新建一個類來實現Connection接口,通過重寫所有的方法來實現一個“可編輯”的Connection,我們稱之為Connection的裝飾者:

public class HoneycombConnectionDecorator implements Connection{

    protected Connection connection;

    protected HoneycombConnectionDecorator(Connection connection) {
        this.connection = connection;
    }

    此處省略對方法實現的三百行代碼...
}

 

 

之后,我們需要新建一個自己的Connection來繼承這個裝飾者,並重寫相應的方法:

public class HoneycombConnection extends HoneycombConnectionDecorator implements HoneycombConnectionSwitcher{
    @Override
    public void close() { do some things }

    @Override
    public boolean isClosed() throws SQLException { do some things }    

    省略...
}

 

 

DataSource的重寫

DataSource是JDK為了更好的統合和管理數據源而定義出的一個規范,獲取連接的入口,方便我們在這一層更好的擴展數據源(例如增加特殊屬性),使我們的連接池的功能更加豐富,我們需要實現一個自己的DataSource

public class HoneycombWrapperDatasource implements DataSource{
    protected HoneycombDatasourceConfig config;
    省略其它方法的實現...
    @Override
    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection(config.getUrl(), config.getUser(), config.getPassword());
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return DriverManager.getConnection(config.getUrl(), username, password);
    }
    省略其它方法的實現...
}

 

 

我們完成了對數據源的實現,但是這里獲取連接的方式是物理創建,我們需要滿足池化的目的,需要重寫HoneycombWrapperDatasource中的連接獲取邏輯,做法是創建一個新的類對父類方法重寫:

 

public class HoneycombDataSource extends HoneycombWrapperDatasource{
    private HoneycombConnectionPool pool;
    @Override
    public Connection getConnection() throws SQLException {
        這里實現從pool中取出連接的邏輯
    }
    省略...
}

 

 特性擴展

在當前結構體系下,我們的連接池逐漸浮現出了雛形,但遠遠不夠的是,我們需要在此結構下可以做自由的擴展,使連接池對連接的控制更加靈活,因此我們可以引入特性這個概念,它允許我們在其內部訪問連接池,並對連接池做一系列的擴展操作:

public abstract class AbstractFeature{
    public abstract void doing(HoneycombConnectionPool pool);
}

 

 

AbstractFeature抽象父類需要實現doing方法,我們可以在方法內部實現對連接池的控制,其中一個典型的例子就是對池中空閑連接左回收:

public class CleanerFeature extends AbstractFeature{
    @Override
    public void doing(HoneycombConnectionPool pool) {
        這里做空閑連接的回收
    }
}

 

 

三,落實計划

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM