最实用的Druid连接池监控扩展:自定义Filter开发指南
你是否还在为数据库连接池的监控数据不够详细而烦恼?是否需要针对特定业务场景定制监控指标?本文将带你从零开始开发一个Druid连接池的自定义Filter,实现个性化监控功能,让你轻松掌握数据库连接的每一个细节。读完本文后,你将能够:
- 理解Druid Filter的工作原理
- 开发并注册自定义Filter
- 实现SQL执行时间监控
- 收集并展示自定义监控指标
Druid Filter基础
Druid连接池(Druid DataSource)的强大之处在于其可扩展的Filter机制。Filter允许开发者在不修改核心代码的情况下,拦截数据库操作并添加自定义逻辑。无论是监控、日志记录还是安全控制,Filter都能胜任。
Filter接口与实现类
Druid的Filter体系主要基于三个核心组件:
-
Filter接口:定义了所有可拦截的数据库操作方法,如连接创建、SQL执行等。完整定义见core/src/main/java/com/alibaba/druid/filter/Filter.java。
-
FilterAdapter类:提供了Filter接口的默认实现,所有方法都直接调用FilterChain的对应方法。开发者只需继承此类并覆盖需要拦截的方法即可。源码位于core/src/main/java/com/alibaba/druid/filter/FilterAdapter.java。
-
FilterChain接口:定义了Filter链的调用机制,确保多个Filter能按顺序执行。详细定义见core/src/main/java/com/alibaba/druid/filter/FilterChain.java。
Filter工作流程
Filter的工作流程可以用以下时序图表示:
开发步骤
1. 创建自定义Filter类
首先,创建一个继承FilterAdapter的类,并重写需要拦截的方法。以下是一个监控SQL执行时间的示例:
package com.alibaba.druid.example.filter;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import java.sql.SQLException;
public class SqlExecutionTimeFilter extends FilterAdapter {
@Override
public void statement_execute(FilterChain chain, StatementProxy statement) throws SQLException {
long startTime = System.currentTimeMillis();
try {
// 调用下一个Filter或目标方法
chain.statement_execute(statement);
} finally {
long executeTime = System.currentTimeMillis() - startTime;
// 记录SQL执行时间
System.out.println("SQL执行时间: " + executeTime + "ms, SQL: " + statement.getSql());
// 这里可以添加自定义监控逻辑,如存入 metrics 或报警
}
}
@Override
public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
long startTime = System.currentTimeMillis();
try {
return chain.preparedStatement_execute(statement);
} finally {
long executeTime = System.currentTimeMillis() - startTime;
System.out.println("SQL执行时间: " + executeTime + "ms, SQL: " + statement.getSql());
}
}
}
2. 注册Filter
创建好Filter后,需要将其注册到DruidDataSource中。有两种常用方式:
方式一:通过代码注册
DruidDataSource dataSource = new DruidDataSource();
// 配置数据源基本信息
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
// 注册自定义Filter
dataSource.getFilters().add(new SqlExecutionTimeFilter());
方式二:通过配置文件注册
在Druid的配置文件中添加:
# 配置Filter
druid.filters=stat,wall,com.alibaba.druid.example.filter.SqlExecutionTimeFilter
其中stat和wall是Druid内置的Filter,分别用于统计监控和SQL防火墙,我们的自定义Filter通过全类名添加。
3. 配置Filter参数(可选)
如果你的Filter需要配置参数,可以通过以下方式:
public class SqlExecutionTimeFilter extends FilterAdapter {
private long slowSqlThreshold = 1000; // 默认慢SQL阈值为1秒
public void setSlowSqlThreshold(long slowSqlThreshold) {
this.slowSqlThreshold = slowSqlThreshold;
}
@Override
public void statement_execute(FilterChain chain, StatementProxy statement) throws SQLException {
long startTime = System.currentTimeMillis();
try {
chain.statement_execute(statement);
} finally {
long executeTime = System.currentTimeMillis() - startTime;
if (executeTime > slowSqlThreshold) {
System.out.println("慢SQL警告: " + executeTime + "ms, SQL: " + statement.getSql());
}
}
}
}
然后在配置文件中设置参数:
druid.filter.sqlExecutionTime.slowSqlThreshold=2000
高级应用:自定义监控指标
除了简单的日志输出,我们还可以将监控数据集成到监控系统中。Druid提供了StatFilter用于收集统计信息,我们可以扩展它来添加自定义指标。
1. 创建自定义StatFilter
public class CustomStatFilter extends StatFilter {
@Override
public void statement_execute(FilterChain chain, StatementProxy statement) throws SQLException {
long startTime = System.currentTimeMillis();
try {
super.statement_execute(chain, statement);
} finally {
long executeTime = System.currentTimeMillis() - startTime;
// 获取SQL对应的统计对象
JdbcSqlStat sqlStat = statement.getDataSource().getSqlStatManager().getSqlStat(statement.getSql());
// 添加自定义指标
sqlStat.addCustomMetrics("custom.execution.time", executeTime);
}
}
}
2. 获取自定义指标
// 获取数据源的SQL统计信息
SqlStatManager sqlStatManager = dataSource.getSqlStatManager();
Collection<JdbcSqlStat> sqlStats = sqlStatManager.getSqlStats();
for (JdbcSqlStat sqlStat : sqlStats) {
System.out.println("SQL: " + sqlStat.getSql());
System.out.println("平均执行时间: " + sqlStat.getCustomMetrics("custom.execution.time").getAvg());
System.out.println("最大执行时间: " + sqlStat.getCustomMetrics("custom.execution.time").getMax());
}
集成Spring Boot
如果你在Spring Boot项目中使用Druid,可以通过以下方式注册自定义Filter:
1. 创建配置类
@Configuration
public class DruidConfig {
@Bean
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
// 注册自定义Filter
dataSource.getFilters().add(new SqlExecutionTimeFilter());
return dataSource;
}
}
2. 使用Spring Boot Starter
如果使用Druid的Spring Boot Starter(druid-spring-boot-starter),可以在application.properties中配置:
spring.datasource.druid.filters=stat,wall,com.alibaba.druid.example.filter.SqlExecutionTimeFilter
常见问题与解决方案
1. Filter不生效
- 检查Filter是否正确注册到DruidDataSource中
- 确保Filter的全类名配置正确
- 检查是否有其他Filter拦截了请求并提前返回
2. 性能影响
- 避免在Filter中执行耗时操作
- 对于复杂逻辑,考虑使用异步处理
- 通过条件判断只对关键SQL进行监控
3. 与其他Filter的顺序问题
Druid的Filter链执行顺序与注册顺序一致,可以通过调整注册顺序来解决Filter间的依赖问题。
总结
通过自定义Filter,我们可以轻松扩展Druid连接池的监控功能,满足特定业务需求。本文介绍了Filter的基本原理、开发步骤和高级应用,希望能帮助你更好地使用Druid连接池。
Druid的Filter机制非常灵活,除了监控外,还可以用于实现SQL重写、数据脱敏、性能优化等功能。更多Filter相关的API可以参考官方文档和源码。
如果你有好的Filter应用场景,欢迎在评论区分享!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



