Java中JDBC可基于DataSource接口、动态代理和线程安全集合构建轻量连接池,核心是代理拦截Connection.close()实现连接归还而非关闭,并确保线程安全与资源清理。

Java 中 JDBC 在没有第三方框架时,可以通过实现 javax.sql.DataSource 接口 + 动态代理 + 线程安全集合,构建一个轻量、可控的简易连接池。核心不是“代理类”本身,而是用代理来拦截 Connection.close() 方法,让释放动作变成“归还到池”,而非真实关闭。
关键设计思路:代理只改 close 行为
真实 Connection 对象由 DriverManager 创建,但直接暴露给业务代码会引发误关。因此需对其做一层包装——不是继承 Connection(不可行),而是用 Proxy.newProxyInstance 生成代理对象,仅重写 close() 方法,其余方法原样委托给原始连接。
- 代理不参与连接创建/销毁逻辑,只负责“语义转换”:调用
close()→ 实际执行pool.add(connection) - 原始 Connection 仍由 JDBC 驱动管理,代理只是它的“外观”
- 必须显式指定
Connection.class接口(而非con.getClass().getInterfaces()),因 DriverManager 返回的是具体实现类(如com.mysql.cj.jdbc.ConnectionImpl),未必实现全部标准接口
连接池主体需实现 DataSource 接口
这是 JDBC 规范要求,也是与上层代码解耦的关键。自定义类(如 MyDataSource)必须实现 getConnection(),并内部维护一个线程安全的连接容器(推荐 Collections.synchronizedList(new ArrayList()) 或 ConcurrentLinkedQueue)。
- 构造时预热:循环调用
JDBCUtils.getConnection()创建初始连接(如 3–5 个),全部加入池中 -
getConnection()方法:从池中移除并返回一个连接;若池空且未达最大数,可动态新建;若已达上限,可阻塞或抛异常 - 提供
returnConnection(Connection con)方法供代理调用,但通常不对外暴露——它由代理内部触发
代理 Connection 的完整 invoke 逻辑
在 InvocationHandler.invoke() 中,需精准识别 close() 调用,并区分其他方法:
立即学习“Java免费学习笔记(深入)”;
- 当
method.getName().equals("close")时:不再调用originalCon.close(),而是执行pool.add(originalCon),完成“归还” - 其他所有方法(
createStatement、prepareStatement、commit等):一律通过method.invoke(originalCon, args)委托执行 - 注意处理
isClosed():代理应返回false(除非你额外维护状态),否则框架可能跳过操作
线程安全与资源清理不能省略
多线程环境下,连接取用和归还必须同步,否则池状态会错乱:
- 连接获取(
pool.remove(0))和归还(pool.add(con))都需保证原子性,用同步块或并发集合 - 建议定期清理失效连接:启动守护线程或在
getConnection()中检查con.isValid(2),剔除已断开的连接 - 避免内存泄漏:代理对象持有原始 Connection 引用,若池长期不清理,可能导致连接堆积;可在归还前调用
con.clearWarnings()和con.rollback()重置状态


















