Druid概述
是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和 SQL 解析器组成,该项目主要是为了扩展 JDBC 的一些限制,可以让实现一些特殊的需求,比如向密钥服务请求凭证、统计 SQL 信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,开发者可以通过定制来实现自己需要的功能。
首先它是一个数据库连接池,但它不仅仅是一个数据库连接池,还包含了一个 ProxyDriver,一系列内置的 JDBC 组件库,一个 SQL Parser。在 Java 的世界中 Druid 是监控做的最好的数据库连接池,在功能、性能、扩展性方面,也有不错的表现。
- 替换其他 Java 连接池,Druid 提供了一个高效、功能强大、可扩展性好的数据库连接池。
- 可以监控数据库访问性能,Druid 内置提供了一个功能强大的 StatFilter 插件,能够详细统计 SQL 的执行性能,这对于线上分析数据库访问性能有很大帮助。
- 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题,DruidDruiver 和 DruidDataSource 都支持 PasswordCallback。
- SQL 执行日志,Druid 提供了不同的 LogFilter,能够支持 Common-Logging、Log4j 和 JdkLog,可以按需要选择相应的 LogFilter,监控应用的数据库访问情况。
- 扩展 JDBC,如果你要对 JDBC 层有编程的需求,可以通过 Druid 提供的 Filter 机制,很方便编写 JDBC 层的扩展插件。
与SpringBoot集成
与SpringBoot的集成非常简单,只需要引入依赖和简单配置一下即可:
引入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<!-- 版本不能太低容易出错 -->
<version>1.1.10</version>
</dependency>
配置application.yml :
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&useSSL=false&characterEncoding=utf-8
username: xCW2az2YmV2w3rfDry543D01dNWo==
password: ta9INTvbFddwsd+4==
druid:
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计.属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat、 日志用的filter:log4j 、防御sql注入的filter:wall、
filters: stat,wall,log4j2
filter: # filter详细配置见: https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter
stat:
log-slow-sql: true # 开启log慢Sql
slow-sql-millis: 1 # slowSqlMillis缺省值为3秒
merge-sql: true # 开启SQL合并 select * from t where id = ?
# 也可以通过connectionProperties 属性来打开Sql合并功能和慢SQL记录
#connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
max-active: 20 # 最大活跃数(最大连接池数量)
initialSize: 2 # 初始化建立物理连接的的数量。初始化发生在显示调用init方法,或者第一次getConnection时
maxWait: 60000 # 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
minIdle: 2 # 最小连接池数量
还需要自定义配置相关Bean:
@Configuration
public class DruidMonitorConfiguration {
/**
* 注册ServletRegistrationBean
*/
@Bean
public ServletRegistrationBean registrationBean() {
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
/** 初始化参数配置,initParams **/
// 白名单
bean.addInitParameter("allow", "127.0.0.1");// 多个ip逗号隔开
// IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not
// permitted to view this page.
// bean.addInitParameter("deny", "192.168.1.73");
// 登录查看信息的账号密码.
// bean.addInitParameter("loginUsername", "root");
// bean.addInitParameter("loginPassword", "root");
// bean.addInitParameter("filters", "stat,wall,log4j");
// 是否能够重置数据.
bean.addInitParameter("resetEnable", "false");
return bean;
}
/**
* 注册一个filterRegistrationBean
*/
@Bean
public FilterRegistrationBean druidStatFilter2(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则.
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息.
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*," +
"/swagger-resources/*,/loginTest/*,/api/*,/webjars/*./webSocketServer/*,/webSocketTest/*,*.html,*.json");
return filterRegistrationBean;
}
@Bean
public DruidStatInterceptor druidStatInterceptor() {
DruidStatInterceptor dsInterceptor = new DruidStatInterceptor();
return dsInterceptor;
}
@Bean
@Scope("prototype")
public JdkRegexpMethodPointcut druidStatPointcut() {
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPatterns(
"fun.lzyz.porject.*"
);
return pointcut;
}
@Bean
public DefaultPointcutAdvisor druidStatAdvisor(DruidStatInterceptor druidStatInterceptor, JdkRegexpMethodPointcut druidStatPointcut) {
DefaultPointcutAdvisor defaultPointAdvisor = new DefaultPointcutAdvisor();
defaultPointAdvisor.setPointcut(druidStatPointcut);
defaultPointAdvisor.setAdvice(druidStatInterceptor);
return defaultPointAdvisor;
}
}
配置logback-spring.xml,记录日志:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration scan="true" monitorInterval="30">
<!-- 等级 TRACE, DEBUG, INFO, WARN, ERROR -->
<contextName>logback</contextName>
<!-- 用来定义变量值的标签,有两个属性,name和value;
· name 变量的名称
· value 变量定义的值。通过定义的值会被插入到logger上下文中。
定义变量后,可以使“${}”来使用变量。 -->
<property name="logDir" value="logs"/>
<property name="appName" value="porject"/>
<property name="logLevel" value="INFO"/>
<!--
appender是一个日志打印的组件,这里组件里面定义了打印过滤的条件,打印输出方式,滚动策略,编码方式,打印格式等等。
但是它仅仅是一个打印组件,我们如果不使用一个logger或者root的appender-ref指定某个具体的appender时,它就没有什么意义。
-->
<!--
appender是一个日志打印的组件,这里组件里面定义了打印过滤的条件,打印输出方式,滚动策略,编码方式,打印格式等等。
但是它仅仅是一个打印组件,我们如果不使用一个logger或者root的appender-ref指定某个具体的appender时,它就没有什么意义。
-->
<!-- 输出到控制台ConsoleLog 一般生产环境都是后台启动,这个没太大作用 -->
<appender name="ConsoleLog" class="ch.qos.logback.core.ConsoleAppender">
<!--展示格式 layout-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50} [line%L]: %msg%n</pattern>
</pattern>
</layout>
</appender>
<!-- 只保存错误日志 -->
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>Error</level>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
的日志改名为今天的日期。即,<File> 的日志都是当天的。
-->
<File>${logDir}/error.${appName}.log</File>
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
<FileNamePattern>${logDir}/erro/erroInfo.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--只保留最近60天的日志-->
<maxHistory>60</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<!--日志输出编码格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
</encoder>
</appender>
<!-- Druid日志 -->
<appender name="DruidFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logDir}/log_druid.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logDir}/druid/log-druid-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<MaxHistory>60</MaxHistory>
</rollingPolicy>
<append>true</append>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="com.alibaba.druid.filter.stat.StatFilter" level="ERROR">
<appender-ref ref="DruidFILE" />
</logger>
<root level="INFO">
<!-- 添加定义好的appender -->
<appender-ref ref="ConsoleLog"/>
<appender-ref ref="fileErrorLog"/>
</root>
</Configuration>
配置好后,访问:
http://[ip]:[port]/druid/index,使用配置的用户名密码登录 。
更多可参考: https://my.oschina.net/zhang2xiang/blog/3108186/print