對象池適用於「創建開銷大、頻繁使用、數量可控」的資源。數據庫連接典型符合:TCP 三次握手 + SSL 握手 + 認證 + 會話初始化,單次耗時 10-100ms;數據庫最大連接數受限(如 MySQL 默認 151)。連接池預創建連接,借用/歸還替代創建/關閉,大幅降低延遲、控制併發。
採用 Builder 模式,區分必選/可選參數,支持鏈式調用:
public class ConnectionParam {
private final String driver, url, user, password;
private final int minConnection, maxConnection, minIdle;
private final long maxWait;
public static class ConnectionParamBuilder implements Builder<ConnectionParam> {
// 必選參數
private final String driver, url, user, password;
// 可選參數默認值
private int minConnection = 5, maxConnection = 50, minIdle = 5;
private long maxWait = 30000;
public ConnectionParamBuilder(String driver, String url, String user, String password) {...}
public ConnectionParamBuilder maxConnection(int v) { this.maxConnection = v; return this; }
// 其他 setter 省略
public ConnectionParam build() { return new ConnectionParam(this); }
}
}
實現 DataSource 接口,雙容器設計:
ArrayBlockingQueue<Connection> idleQueue:有界阻塞隊列,存放空閒連接,支持超時獲取。Vector<Connection> busyVector:同步列表,追蹤活躍連接。關鍵創新:動態代理攔截 close()
@Override
public Connection getConnection() throws SQLException {
Connection rawConn = idleQueue.poll(maxWait, TimeUnit.MILLISECONDS);
if (rawConn == null) { ensureCapacity(); return null; }
busyVector.add(rawConn);
return (Connection) Proxy.newProxyInstance(
getClass().getClassLoader(),
new Class[]{Connection.class},
(proxy, method, args) -> {
if (!"close".equals(method.getName()))
return method.invoke(rawConn, args);
// 歸還而非關閉
idleQueue.offer(rawConn);
busyVector.remove(rawConn);
return null;
}
);
}
擴容策略:ensureCapacity() 按 minIdle 批量補充,不超 maxConnection。
線程安全的 ConcurrentHashMap<String, ConnectionPool> 管理多個命名池:
public static Connection getConnection(String poolName) throws SQLException {
ConnectionPool pool = poolMap.get(poolName);
if (pool == null) throw new IllegalArgumentException("Pool not found: " + poolName);
return pool.getConnection();
}
public static void registerConnectionPool(String name, ConnectionParam param) {
if (poolMap.containsKey(name)) throw new IllegalArgumentException("Pool exists: " + name);
poolMap.put(name, new ConnectionPool(param));
}
public static void unRegisterConnectionPool(String name) {
ConnectionPool pool = poolMap.remove(name);
if (pool != null) new Thread(pool::clear).start(); // 異步銷毀
}
database.config.ParamConfiguration // 常量默認值
database.Builder // 構建器接口
database.ConnectionParam // 參數實體 + Builder
database.factory.ConnectionPool // 連接池實現 (DataSource)
database.factory.ConnectionPoolFactory // 工廠管理類
database.factory.ConnectionPoolFactoryTest // JUnit 測試
@Test
public void testGetConnection() throws SQLException {
// 註冊池
ConnectionParam param = new ConnectionParam.ConnectionParamBuilder(
"com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/test", "root", "root"
).build();
ConnectionPoolFactory.registerConnectionPool("test", param);
// 併發獲取 12 個連接
List<Connection> conns = new ArrayList<>();
for (int i = 0; i < 12; i++) conns.add(ConnectionPoolFactory.getConnection("test"));
printStats(); // idle=5, busy=12, size=17 (初始5+擴容7+minIdle5=17)
// 歸還
for (Connection c : conns) if (c != null) c.close();
printStats(); // idle=17, busy=0, size=17
// 二次獲取驗證復用
conns.clear();
for (int i = 0; i < 12; i++) conns.add(ConnectionPoolFactory.getConnection("test"));
printStats(); // idle=5, busy=12, size=17
ConnectionPoolFactory.unRegisterConnectionPool("test");
}
| 維度 | 教學版 | 生產級 (HikariCP/Druid) |
|---|---|---|
| 連接驗證 | 無 | 空閒檢測、存活測試、驗證查詢 |
| 洩漏檢測 | 無 | 堆棧追蹤定位未歸還連接 |
| PreparedStatement 緩存 | 無 | 每連接 LRU 緩存 |
| 指標監控 | 無 | JMX/Prometheus/內建監控頁 |
| 動態配置 | 無 | 運行時調整池大小 |
| 高可用 | 無 | 熔斷、降級、多數據源負載均衡 |
手寫連接池是理解「資源池化、動態代理、併發容器、JDBC 規範」的最佳途徑。生產環境請直接使用 HikariCP(Spring Boot 2.x 默認)或 Druid(阿里巴巴出品,監控強),兩者經過億級流量驗證,性能與穩健性遠超教學實現。