首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 動態代理實現資料庫連線池:攔截 close() 實現透明連線回收

     編輯:Java 相關知識

傳統連線池痛點

  1. 強制使用者呼叫專屬 release() 而非標準 Connection.close(),改變使用習慣。
  2. 若使用者誤呼叫 close(),連線池無法感知,導致連線洩漏與狀態不一致。

解決方案:動態代理攔截 close()

利用 java.lang.reflect.Proxy 為真實 Connection 建立代理,攔截 close() 轉為「標記閒置歸還池中」,而非真正關閉底層連線。

核心架構

  • ConnectionParam:封裝驅動、URL、帳密、池大小等配置。
  • ConnectionFactory:單例工廠,管理多個命名連線池(bind/lookup/unbind)。
  • DataSourceImpl:實作 javax.sql.DataSource,內部維護兩個集合:FreeConnectionPool、BusyConnectionPool。
  • _Connection:實作 InvocationHandler,包裝真實連線,攔截 close()、createStatement()、prepareStatement()、事務方法。

關鍵程式碼:_Connection 代理邏輯

class _Connection implements InvocationHandler {
    private static final String CLOSE = "close";
    private final Connection realConn;
    private Statement stmtRef;
    private PreparedStatement pstmtRef;
    private boolean inUse = false;

    _Connection(ConnectionParam param) { /* 建立真實連線 */ }

    public Connection getProxy() {
        return (Connection) Proxy.newProxyInstance(
            realConn.getClass().getClassLoader(),
            realConn.getClass().getInterfaces(),
            this
        );
    }

    @Override
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        String name = m.getName();
        if (CLOSE.equals(name)) {
            inUse = false; // 歸還池中
            closeStatements(); // 關閉關聯 Statement
            return null;
        }
        if ("createStatement".equals(name)) {
            Object stmt = m.invoke(realConn, args);
            stmtRef = (Statement) stmt;
            return stmt;
        }
        if ("prepareStatement".equals(name)) {
            Object ps = m.invoke(realConn, args);
            pstmtRef = (PreparedStatement) ps;
            return ps;
        }
        // 事務方法若不支援則忽略
        if (("commit".equals(name) || "rollback".equals(name)) && !supportsTransactions) return null;
        return m.invoke(realConn, args);
    }

    void reallyClose() throws SQLException { realConn.close(); } // 池關閉時真正釋放
}

DataSourceImpl 取得連線流程

public Connection getConnection() throws SQLException {
    _Connection wrapper = getFreeWrapper(); // 從閒置池取出或新建
    wrapper.inUse = true;
    moveToBusyPool(wrapper);
    return wrapper.getProxy(); // 回傳代理
}

池管理策略

  • 靜態管理:取用時檢查閒置池,不足則新建(未達上限)。
  • 動態管理:背景執行緒定期檢查,回收超時連線、補充閒置池至最小值。

使用者視角:零差異體驗

DataSource ds = ConnectionFactory.lookup("pool");
Connection conn = ds.getConnection(); // 標準 API
try {
    PreparedStatement ps = conn.prepareStatement(sql);
    ps.executeUpdate();
} finally {
    conn.close(); // 實際歸還池中,非關閉
}

完美解決兩大痛點:保留標準 JDBC 習慣、連線池完全掌控連線生命週期。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved