Druid介绍
Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
同时Druid不仅仅是一个数据库连接池,它包括三个部分:
1.基于Filter-Chain模式的插件体系。
2.DruidDataSource 高效可管理的数据库连接池。
3.SQLParser
Druid可以做什么?
- 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
- 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
- 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
- SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter-Chain机制,很方便编写JDBC层的扩展插件。
Springboot集成druid
Springboot集成Druid方案:
1、在POM中直接配置druid-spring-boot-starter,不需要添加监控的话不需要写额外代码。
2、配置druid,写几行代码,可以加入;
- 环境介绍:
MySQL5.7
SpringBoot-2.5.3
集成步骤
只列出关键部分代码,详细看完整源码,文章末尾有链接。
- 利用Spring Initializr创建一个springboot项目:druid_demo
- pom添加druid数据源依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
- 配置Druid数据源属性文件
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useSSL=false
username: root
password: root123
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 20
# 配置获取连接等待超时的时间
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
# sql 校验
validation-query: select count(1) from sys.objects Where type='U' And type_desc='USER_TABLE'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
max-pool-prepared-statement-per-connection-size: 20
filters: stat # wall 若开启 wall,会把 if 中的 and 判断为注入进行拦截
use-global-data-source-stat: true
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
- 添加Druid的配置类
@Configuration
public class DruidConfig {
/**
* 配置 Druid 监控管理后台的Servlet;
* 内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 的父类
// com.alibaba.druid.support.http.ResourceServlet 中找到
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow",""); //默认就是允许所有访问
//deny:Druid 后台拒绝谁访问,表示禁止此ip访问
// initParams.put("deny","192.168.10.132");
bean.setInitParameters(initParams);
return bean;
}
/**
* 配置一个web监控的filter
*/
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
- 添加业务类
这是一个访问用户列表的接口:
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
UserService userService;
@GetMapping("/list")
public List<User> list(){
return userService.list(null);
}
}
- 启动,访问localhost:9000/user/list
- 访问localhost:9000/druid 进入druid数据源监控系统
- 查看SQL监控
实现密码加密
目前配置文件中配置的数据库用户名和密码都是明文的,这在某些情况下是不被允许的,那正好druid可以对其进行加密,按以下操作即可:
- 利用工具类生成加密后密码和公钥
public static void main(String[] args) throws Exception {
String password = "root123";
System.out.println("明文密码: " + password);
String[] keyPair = ConfigTools.genKeyPair(512);
//私钥
String privateKey = keyPair[0];
//公钥
String publicKey = keyPair[1];
//用私钥加密后的密文
password = ConfigTools.encrypt(privateKey, password);
System.out.println("privateKey:" + privateKey);
System.out.println("publicKey:" + publicKey);
System.out.println("password:" + password);
String decryptPassword = ConfigTools.decrypt(publicKey, password);
System.out.println("解密后:" + decryptPassword);
}
运行后得到:
- 修改配置文件
用上面得到的密码和publicKey替换配置文件中的密文:
- 修改DruidConfig配置类
添加以下自定义Druid数据源配置:
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.type}")
private String type;
@Value("${spring.datasource.publicKey}")
private String publicKey;
@Value("${spring.datasource.druid.initial-size}")
private Integer initialSize;
@Value("${spring.datasource.druid.min-idle}")
private Integer minIdle;
@Value("${spring.datasource.druid.max-active}")
private Integer maxActive;
@Value("${spring.datasource.druid.max-wait}")
private Integer maxWait;
@Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
private Integer timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.min-evictable-idle-time-millis}")
private Integer minEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.validation-query}")
private String validationQuery;
@Value("${spring.datasource.druid.test-while-idle}")
private Boolean testWhileIdle;
@Value("${spring.datasource.druid.test-on-borrow}")
private Boolean testOnBorrow;
@Value("${spring.datasource.druid.test-on-return}")
private Boolean testOnReturn;
@Value("${spring.datasource.druid.pool-prepared-statements}")
private Boolean poolPreparedStatements;
@Value("${spring.datasource.druid.max-pool-prepared-statement-per-connection-size}")
private Integer maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.druid.filters}")
private String filters;
@Value("${spring.datasource.druid.use-global-data-source-stat}")
private Boolean useGlobalDataSourceStat;
@Value("${spring.datasource.druid.connect-properties}")
private Properties connectProperties;
@Bean
@Primary
public DataSource druidDataSource() throws Exception {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
// 解密后,再 set 进对象
datasource.setPassword(ConfigTools.decrypt(publicKey, password));
logger.info("密码:" + ConfigTools.decrypt(publicKey, password));
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
datasource.setConnectProperties(connectProperties);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("========druid configuration initialization filter========", e);
}
return datasource;
}
- 启动项目,访问:localhost:9000/user/list测试正常返回数据即可。
注意:druid利用的反向非对称加密机制,也就是私钥加密,用公钥解密。
项目源码
https://gitee.com/indexman/druid_demo