Druid连接池使用和源码分析
Druid是阿里巴巴开源的一款高性能数据库连接池,它不仅拥有出色的性能,还提供了强大的监控和防御SQL注入功能。本文将从使用方法、配置参数、架构设计和源码分析四个方面深入探讨Druid,帮助你全面掌握这一国产优秀开源组件。
一、Druid连接池的使用方法与配置
1. 添加依赖
Maven项目中添加以下依赖:
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>
2. 基本配置与使用
以下是一个基本的Druid连接池配置示例:
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;public class DruidExample {public static void main(String[] args) {// 创建数据源DruidDataSource dataSource = new DruidDataSource();// 配置数据库连接信息dataSource.setUrl("jdbc:mysql://localhost:3306/mydatabase");dataSource.setUsername("root");dataSource.setPassword("password");// 配置连接池参数dataSource.setInitialSize(5); // 初始化连接数dataSource.setMaxActive(20); // 最大连接数dataSource.setMinIdle(5); // 最小空闲连接数dataSource.setMaxWait(60000); // 获取连接的最大等待时间(毫秒)dataSource.setTimeBetweenEvictionRunsMillis(60000); // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接dataSource.setMinEvictableIdleTimeMillis(300000); // 配置一个连接在池中最小生存的时间dataSource.setValidationQuery("SELECT 1"); // 验证连接有效性的SQLdataSource.setTestWhileIdle(true); // 连接空闲时是否进行有效性检测dataSource.setTestOnBorrow(false); // 获取连接时是否进行有效性检测dataSource.setTestOnReturn(false); // 归还连接时是否进行有效性检测try (Connection connection = dataSource.getConnection();Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery("SELECT * FROM users")) {while (resultSet.next()) {System.out.println("ID: " + resultSet.getInt("id") + ", Name: " + resultSet.getString("name"));}} catch (Exception e) {e.printStackTrace();} finally {// 关闭数据源dataSource.close();}}
}
3. 常用配置参数说明
参数名 | 默认值 | 说明 |
---|---|---|
url | - | 数据库连接URL |
username | - | 数据库用户名 |
password | - | 数据库密码 |
initialSize | 0 | 初始化连接数 |
maxActive | 8 | 最大连接数 |
minIdle | 0 | 最小空闲连接数 |
maxWait | -1 | 获取连接的最大等待时间(毫秒),-1表示无限等待 |
timeBetweenEvictionRunsMillis | 60000 | 配置间隔多久才进行一次检测,检测需要关闭的空闲连接 |
minEvictableIdleTimeMillis | 300000 | 配置一个连接在池中最小生存的时间 |
validationQuery | - | 验证连接有效性的SQL |
testWhileIdle | true | 连接空闲时是否进行有效性检测 |
testOnBorrow | false | 获取连接时是否进行有效性检测 |
testOnReturn | false | 归还连接时是否进行有效性检测 |
poolPreparedStatements | false | 是否缓存PreparedStatement |
maxPoolPreparedStatementPerConnectionSize | -1 | 每个连接最多缓存的PreparedStatement数量 |
filters | - | 配置监控统计拦截的filters,如stat,wall,log4j |
二、Druid连接池架构设计
Druid连接池的架构设计融合了高性能与丰富的功能特性,其核心组件包括:
-
DruidDataSource:数据源实现类,继承自
javax.sql.DataSource
,作为连接池的入口点。 -
DruidConnectionHolder:连接持有者,包装了实际的数据库连接,并存储连接的元信息。
-
DruidPooledConnection:代理连接类,实现了对实际数据库连接的代理,负责连接的生命周期管理。
-
DruidAbstractDataSource:抽象数据源类,定义了数据源的基本行为和属性。
-
DruidConnectionPool:连接池的核心实现,负责连接的创建、获取、归还和销毁。
-
DestroyTask:后台线程,负责监控空闲连接和超时连接,定期清理和维护连接池。
-
FilterChainManager:过滤器链管理器,负责管理和执行各种过滤器,提供监控、防御SQL注入等功能。
Druid连接池架构组件关系图:
┌─────────────────────┐
│ DruidDataSource │
└───────────┬─────────┘│▼
┌─────────────────────┐
│ DruidConnectionPool │
├─────────────────────┤
│ - CreateConnectionThread │
│ - DestroyTask Thread │
│ - DruidConnectionHolder List │
└───────────┬─────────┘│▼
┌─────────────────────┐
│ DruidPooledConnection │
├─────────────────────┤
│ - FilterChain │
└───────────┬─────────┘│▼
┌─────────────────────┐
│ FilterChainManager │
├─────────────────────┤
│ - StatFilter │
│ - WallFilter │
│ - LogFilter │
└─────────────────────┘
三、Druid连接池源码分析
1. 初始化过程
Druid连接池的初始化过程主要在DruidDataSource
类中完成:
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, Referenceable, Closeable {// 初始化方法public void init() throws SQLException {if (inited) {return;}// 获取锁,确保单线程初始化final ReentrantLock lock = this.lock;lock.lock();try {// 再次检查是否已初始化if (inited) {return;}// 初始化配置initConfig();// 初始化连接池initStat();initConnections();initCreateThread();initDestroyThread();// 标记为已初始化inited = true;} finally {lock.unlock();}}
}
关键步骤包括:
- 配置参数的初始化和验证
- 创建初始连接
- 启动创建连接和销毁连接的后台线程
2. 连接获取过程
当调用getConnection()
方法时,实际执行的是DruidDataSource
的getConnection()
方法:
public Connection 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);}
}
连接获取的核心逻辑:
- 如果配置了过滤器,创建过滤链并通过过滤链获取连接
- 否则直接从连接池获取连接
- 处理连接超时和连接有效性验证
3. 连接池管理
Druid通过DestroyTask
线程定期清理和维护连接池:
public class DestroyTask implements Runnable {@Overridepublic void run() {shrink(true, keepAlive);if (isRemoveAbandoned()) {removeAbandoned();}}
}
DestroyTask
线程的主要职责:
- 收缩连接池,关闭空闲时间超过阈值的连接
- 移除超时的废弃连接,防止内存泄漏
4. 过滤器机制
Druid的过滤器机制是其一大特色,通过过滤器可以实现监控、防御SQL注入等功能:
public interface Filter {// 连接相关方法Connection proxyConnection(FilterChain chain, DruidConnectionHolder holder) throws SQLException;// Statement相关方法Statement proxyStatement(FilterChain chain, Statement statement) throws SQLException;// PreparedStatement相关方法PreparedStatement proxyPrepareStatement(FilterChain chain, String sql) throws SQLException;// ResultSet相关方法ResultSet proxyResultSet(FilterChain chain, ResultSet resultSet) throws SQLException;
}
常用的过滤器:
- StatFilter:统计监控过滤器,收集SQL执行性能数据
- WallFilter:防御SQL注入过滤器,提供SQL防火墙功能
- LogFilter:日志过滤器,记录SQL执行日志
四、Druid连接池的特色功能
1. 监控统计功能
Druid提供了强大的监控统计功能,可以通过配置开启:
// 配置监控统计拦截的filters
dataSource.setFilters("stat");// 配置StatFilter
StatFilter statFilter = new StatFilter();
statFilter.setSlowSqlMillis(1000); // 慢SQL定义,超过1秒的SQL为慢SQL
statFilter.setLogSlowSql(true); // 记录慢SQL
dataSource.getProxyFilters().add(statFilter);
通过Druid的监控界面,可以查看:
- SQL执行次数和执行时间统计
- 连接池状态监控
- 慢SQL日志
- 并发连接监控
2. SQL防火墙功能
通过配置WallFilter,可以防御SQL注入攻击:
// 配置WallFilter
WallConfig wallConfig = new WallConfig();
wallConfig.setMultiStatementAllow(true); // 允许批量SQL
wallConfig.setNoneBaseStatementAllow(true); // 允许非基本语句WallFilter wallFilter = new WallFilter();
wallFilter.setConfig(wallConfig);
dataSource.getProxyFilters().add(wallFilter);
3. 配置加密功能
Druid支持数据库密码加密,保护敏感信息:
// 生成加密密码
String password = "your_password";
String[] arr = ConfigTools.genKeyPair(512);
String publicKey = arr[0];
String privateKey = arr[1];
String encryptedPassword = ConfigTools.encrypt(privateKey, password);// 配置加密密码
dataSource.setPassword(encryptedPassword);
dataSource.setConnectionProperties("config.decrypt=true;config.decrypt.key=" + publicKey);
五、总结
Druid连接池凭借其高性能、丰富的功能和良好的扩展性,成为了企业级Java应用的理想选择。通过深入理解其使用方法、配置参数、架构设计和源码实现,我们可以更好地在项目中应用和优化Druid,提高数据库访问性能和安全性。
主要关键点:
- 使用简单:通过
DruidDataSource
配置连接池参数,获取数据库连接 - 配置灵活:提供丰富的配置参数,满足各种场景需求
- 功能强大:内置监控统计、SQL防火墙、连接池管理等功能
- 架构优雅:采用过滤器链设计,便于功能扩展
- 源码精妙:深入学习其源码可以了解到许多高性能编程和安全防御技巧
在实际项目中,建议根据应用的负载特性和安全需求,合理调整Druid的配置参数,并充分利用其监控和安全功能,保障系统的稳定运行。