整体架构
Druid 的关键设计是把“获得连接”和“使用连接”分开:池管理物理连接生命周期,代理对象承载 JDBC 行为,过滤器链把安全、统计和自定义逻辑插入调用路径。
先给答案:Druid 的关键设计是把“获得连接”和“使用连接”分开:池管理物理连接生命周期,代理对象承载 JDBC …
Section titled “先给答案:Druid 的关键设计是把“获得连接”和“使用连接”分开:池管理物理连接生命周期,代理对象承载 JDBC …”Druid 的关键设计是把“获得连接”和“使用连接”分开:池管理物理连接生命周期,代理对象承载 JDBC 行为,过滤器链把安全、统计和自定义逻辑插入调用路径。 正文沿“分层 -> 主流程:一次查询 -> 核心边界”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。
主要失效边界集中在“DruidDataSource 管理物理连接,DruidPooledConnection 管理一次租借。、FilterChain 管理横切逻辑顺序,WallProvider 管理 SQL 策略。、Web 层只读取 DruidDataSourceStatManager,不直接操作池内队列。”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。
Application | vDruidPooledConnection / Statement / ResultSet |ConnectionProxyImpl -> FilterChainImpl -> raw JDBC object | | +---- StatFilter / WallFilter / custom Filter |DruidDataSource |idle holders <--------> active holders| 层 | 职责 | 关键类 |
|---|---|---|
| 池层 | 借出、归还、创建和销毁物理连接 | DruidDataSource |
| 代理层 | 保持 JDBC API 兼容并拦截调用 | ConnectionProxyImpl |
| 链层 | 顺序调用过滤器并落到 raw JDBC | FilterChainImpl |
| 语义层 | 解析、检查和统计 SQL | SQLUtils、WallProvider、StatFilter |
| 展示层 | 暴露统计与管理操作 | StatViewServlet |
主流程:一次查询
Section titled “主流程:一次查询”getConnection -> DruidPooledConnection -> createStatement / prepareStatement -> FilterChainImpl -> WallFilter.check + StatFilter.before -> raw Statement.execute -> StatFilter.after -> ResultSet proxyDruidDataSource#getConnection在core/src/main/java/com/alibaba/druid/pool/DruidDataSource.java:1339进入借连接流程。getConnectionDirect在:1373执行校验、重试和超时判断。DruidPooledConnection#createStatement在DruidPooledConnection.java:655创建代理 Statement。ConnectionProxyImpl#createStatement在ConnectionProxyImpl.java:166将调用交给链。FilterChainImpl#statement_execute在FilterChainImpl.java:617逐个推进过滤器。- 链末端调用 raw JDBC;
StatFilter在StatFilter.java:415附近记录执行前后状态。 DruidPooledConnection#close在DruidPooledConnection.java:236不直接关闭物理连接,而是进入回收。
DruidDataSource管理物理连接,DruidPooledConnection管理一次租借。FilterChain管理横切逻辑顺序,WallProvider管理 SQL 策略。- Web 层只读取
DruidDataSourceStatManager,不直接操作池内队列。
为什么用多层代理而不是只代理 DataSource
Section titled “为什么用多层代理而不是只代理 DataSource”替代方案:只包装 DataSource#getConnection,把所有逻辑放在连接返回前。
为什么不行:SQL 执行发生在 Statement 和 ResultSet 生命周期中,慢 SQL、错误、行数和资源泄漏都需要更细粒度的事件。
证据:ConnectionProxyImpl.java:166、StatementProxyImpl.java:135 和 Filter.java:178 分别覆盖连接、执行和结果集事件。
| 场景 | 现象 | 原因 | 规避 |
|---|---|---|---|
| 代理关闭 | 业务以为连接已物理关闭 | close 语义是归还池 |
不要在连接关闭后继续使用代理 |
| Filter 顺序 | 统计或防火墙行为变化 | 链是有序的 | 固定 WallFilter、StatFilter 的装配顺序 |
| 直接拿 raw connection | 监控缺失 | 绕过代理链 | 不要依赖内部 raw 对象 |
资源管理、调用拦截和业务横切逻辑可以分成三层。只要每层通过稳定接口连接,连接池、RPC 客户端和文件句柄管理都能复用这个结构。
面试锚点
- Druid 的池、代理、过滤器三层分别解决什么问题?
- 为什么
Connection.close()不等于物理连接关闭?- FilterChain 的末端为什么必须保留 raw JDBC 调用?