目录


回到顶部

一、项目介绍

1. Druid 简介

Druid 是阿里巴巴开源的数据库连接池项目。该连接池专为监控而生,内置强大的监控功能,且监控特性不影响性能。Druid 功能强大,支持防 SQL 注入,内置 Logging 机制能诊断黑客应用行为。

2. 模块划分

源码中的模块描述如下:

  • filter:增加自定义的扩展能力。
  • mock:测试模块,可以使用 mock 模块做一些模拟测试。
  • pool:核心模块,入口是 DruidDataSource
  • proxy:代理层。
  • sql:负责 SQL 解析的工作。
  • stat:扩展能力实现,例如基于 filter 的监控,真正的实现在 stat 文件夹。
  • support:一些附加功能,比如 JSON 解析等。
  • util:工具类。
  • wall:防火墙相关,防止 SQL 注入等操作。但实际上对于现在的项目,SQL 注入通常在网关层做了处理,不会真正到数据库连接池层面再做处理。

Druid 模块结构图

二、快速概览 DruidDataSource 数据结构

pool 是 Druid 中最核心的目录,而 DruidDataSource 是 pool 中最关键的类之一,其承载了连接池的启动、关闭,以及连接的获取和管理等功能。

DruidDataSource 继承了 DruidAbstractDataSource,两个类内部有大量的变量,用来设置连接池的各种参数。

三、DruidDataSource 入口概览

连接池在使用时最主要就是获取连接,然后使用连接查询操作数据库,那么获取连接基本上就可以作为连接池的一个入口。

DruidConnectionHolder 是连接池中物理连接的载体。在 DruidDataSource 中,获取连接的 getConnection 方法,拿到的是 DruidPooledConnection

@Override
public DruidPooledConnection getConnection() throws SQLException {
    return getConnection(maxWait);
}

public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
    init();

    if (filters.size() > 0) {
        FilterChainImpl filterChain = new FilterChainImpl(this);
        return filterChain.dataSource_connect(this, maxWaitMillis);
    } else {
        return getConnectionDirect(maxWaitMillis);
    }
}

从上述代码可以看到,其首先调用了 init() 方法对连接池做了初始化,然后从连接池中获取连接。获取连接实际调用的是 getConnectionDirect() 方法,在该方法中调用了 getConnectionInternal() 方法获取连接。

四、常见问题

关于使用过程中的常见问题,可参考官方 Wiki:

五、监控及日志

META-INF/druid-filter.properties 文件中配置 Filter 的别名。

配置别名Filter 类名
defaultcom.alibaba.druid.filter.stat.StatFilter
statcom.alibaba.druid.filter.stat.StatFilter
mergeStatcom.alibaba.druid.filter.stat.MergeStatFilter
encodingcom.alibaba.druid.filter.encoding.EncodingConvertFilter
log4jcom.alibaba.druid.filter.logging.Log4jFilter
log4j2com.alibaba.druid.filter.logging.Log4j2Filter
slf4jcom.alibaba.druid.filter.logging.Slf4jLogFilter
commonloggingcom.alibaba.druid.filter.logging.CommonsLogFilter
wallcom.alibaba.druid.wall.WallFilter

实现的基础组件

Filter 列表

  • 接口Filter
  • 抽象类FilterEventAdapter

思考

关于数据库加密的思考:

企业微信截图_数据库加密

六、SQL 抽象语法树 AST

SQL 语法解析树

重要接口

  • SQLASTVisitor

实例讲解

动态修改 SQL

SQL Server 查询添加 nolock

image.png

修改表名称分表

Map<String, String> mapping = Collections.singletonMap("user", "user_01");
String sql2 = "select * from user";
String result2 = SQLUtils.refactor(sql2, JdbcConstants.MYSQL, mapping);

添加分页

String result = PagerUtils.limit(sql, JdbcConstants.SQL_SERVER, 5, 10);
// Assert.assertEquals("SELECT TOP 10 *"
//         + "\nFROM test t WITH (nolock)", result);

添加权限,where 添加用户 ID

SQLUtils.addCondition("select * from t", "userId = 8", null);

添加加密函数 SQL 加密

AES_ENCRYPT(#{driverName}

说明

  • 本文基于 Druid 经典架构整理,具体配置属性与接口可能随版本更新有所变化,请以官方最新文档为准。
  • 关于 SQL 注入防护(WallFilter),现代架构通常建议在网关层或应用层统一处理,连接池层面的防护可作为补充安全措施。