第4篇-Druid过滤链与监控统计
约 1354 字大约 5 分钟
2026-05-24
四、如何配置 Druid 过滤链?
4.1 在 Spring Boot 中配置
在 application.yml 中配置:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/test
username: root
password: password
druid:
# 【核心】配置过滤器(重要!)
filters: stat,wall,log4j2
# 【核心】监控统计配置
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin
# 【核心】防火墙配置
wall:
enabled: true
config:
multi-statement-allow: true # 是否允许一次执行多个 SQL
# 【核心】监控统计配置
stat:
enabled: true
log-slow-sql: true # 是否记录慢查询
slow-sql-millis: 5000 # 慢查询阈值(毫秒)4.2 过滤器配置说明
stat:启用监控统计过滤器。会记录 SQL 执行时间、执行次数等信息。wall:启用 SQL 防火墙过滤器。会检查 SQL 是否包含恶意代码。log4j2:启用日志过滤器。会把 SQL 执行信息输出到日志中。
你可能会问:过滤器的顺序是重要的吗?是的!过滤器的顺序决定了它们的执行顺序。比如:
- 先执行
wall过滤器(检查 SQL 是否合法)。 - 再执行
stat过滤器(记录 SQL 执行时间)。 - 最后执行
log4j2过滤器(输出日志)。
如果顺序反了,可能导致:恶意 SQL 还没检查,就已经执行了(那就尴尬了)。
五、埋下伏笔:MyBatis 如何与 Druid 协作?
说到这里,你可能会问:MyBatis 是如何使用 Druid 连接池的?它又是如何被 Druid 过滤链拦截的?
这个问题,我们会在系列三(MyBatis 系列)中详细解答。这里先预告一下核心流程:
- MyBatis 通过
SqlSession执行 SQL。 SqlSession内部使用了Executor(执行器)。Executor在执行 SQL 前,会通过SpringManagedTransaction获取数据库连接。SpringManagedTransaction会通过DataSourceUtils.getConnection()获取连接。DataSourceUtils.getConnection()最终调用dataSource.getConnection(),也就是 Druid 的getConnection()方法。- 获取到连接后,MyBatis 会创建
Statement(或PreparedStatement),这时就会触发 Druid 的过滤链(比如stat过滤器会记录 SQL 执行时间)。
下一篇文章的预告:《数据源系列(五):MySQL 驱动的 JDBC 实现》
六、总结与思考
今天我们一起深入了 Druid 的过滤链机制,了解了 FilterChainImpl 和 WallFilter 的源码实现,以及监控统计的工作原理。
让我们用几个问题来检验一下今天的学习成果:
Druid 过滤链是如何工作的?
- 使用责任链模式,
FilterChainImpl维护一个pos索引,指向下一个要执行的过滤器。 - 每个过滤器都可以选择:继续执行链,或者中断传递。
- 所有过滤器都执行完后,就调用底层的 JDBC 方法(比如
prepareStatement())。
- 使用责任链模式,
WallFilter 的作用是什么?
- 防止 SQL 注入攻击。
- 限制危险 SQL(比如
DROP TABLE)。 - 根据数据库类型加载对应的防火墙配置。
Druid 监控统计是如何实现的?
- 通过
StatFilter实现。 - 在 SQL 执行前记录开始时间,执行后记录结束时间,计算执行时间。
- 更新
JdbcSqlStat中的统计信息(执行次数、异常次数、执行时间分布等)。
- 通过
如何查看 Druid 监控统计?
- 访问
http://localhost:8080/druid/(默认地址)。 - 登录后(默认用户名/密码:
admin/admin),就能看到各种监控信息。
- 访问
七、扩展阅读
【扩展点】自定义过滤器
Druid 允许你自定义过滤器,实现特殊的业务逻辑。比如,你可以实现一个过滤器,用于动态数据源切换(根据 SQL 类型,路由到不同的数据源)。
// 【扩展点】自定义过滤器示例:动态数据源切换
public class MyDynamicDataSourceFilter extends FilterAdapter {
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
// 【注意】如果 SQL 是 SELECT,就路由到从库
if (sql.trim().toUpperCase().startsWith("SELECT")) {
// 【核心】切换到从库数据源
DataSource slaveDataSource = getSlaveDataSource();
Connection slaveConnection = slaveDataSource.getConnection();
return slaveConnection.prepareStatement(sql);
}
// 【注意】否则,就路由到主库
return chain.connection_prepareStatement(connection, sql);
}
}场景:读写分离!主库负责写操作(INSERT、UPDATE、DELETE),从库负责读操作(SELECT)。通过自定义过滤器,你可以实现自动读写分离,而不用修改业务代码。
如何启用自定义过滤器? 在 application.yml 中配置:
spring:
datasource:
druid:
filters: stat,wall,com.example.MyDynamicDataSourceFilter好了,今天的文章就到这里。下一篇,我们将深入 MySQL 驱动的 JDBC 实现,看看 Driver.connect() 方法到底做了什么。敬请期待!
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发!你的支持是我继续创作的动力!
系列文章目录:
- 系列一:Spring 事务系列(已完成)
- 第1篇:@Transactional 注解的"前世今生"
- 第2篇:AOP 代理 —— 事务的"隐身衣"
- 第3篇:事务传播机制源码深度解析
- 第4篇:事务隔离级别的实现原理
- 第5篇:事务管理器的设计哲学
- 第6篇:事务资源的绑定与传递
- 第7篇:提交、回滚与异常规则
- 系列二:数据源系列(进行中)
- 第1篇:JDBC 规范与 DriverManager 的 legacy(已完成)
- 第2篇:Druid 连接池的整体架构(已完成)
- 第3篇:连接的借与还(getConnection 全流程)(已完成)
- 第4篇:Druid 过滤链与监控统计(本文)
- 第5篇:MySQL 驱动的 JDBC 实现
- 第6篇:连接的生命周期与事务边界
- 系列三:MyBatis 系列(待开始)
- 系列四:总结系列(待开始)