当前位置: > > > SpringBoot - 开启Druid监控统计功能教程(SQL监控、慢SQL记录、去广告)

SpringBoot - 开启Druid监控统计功能教程(SQL监控、慢SQL记录、去广告)

    Druid 是目前 Java 语言中最好的数据库连接池,同时 Druid 还提供强大的监控和扩展功能。下面演示如何打开 Druid 的监控统计功能,并访问内置的监控页面。

1,添加依赖

首先编辑项目的 pom.xml 文件,添加 druid 依赖(如果之前已经加了则跳过这一步骤):
<!-- 数据库连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.22</version>
</dependency>

2,配置属性

    编辑项目的 applicaiton.propertiesapplicaiton.yml 文件,除了配置 JDBC 连接信息外,还需要配置 druid 过滤器、WebStatFilter 以及 StatViewServlet 相关参数信息:
##### JDBC 配置 #######
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/hangge2?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=hangge1234

##### 连接池配置 #######
# 过滤器设置(第一个stat很重要,没有的话会监控不到SQL)
spring.datasource.druid.filters=stat,wall,log4j2

##### WebStatFilter配置 #######
#启用StatFilter
spring.datasource.druid.web-stat-filter.enabled=true
#添加过滤规则
spring.datasource.druid.web-stat-filter.url-pattern=/*
#排除一些不必要的url
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
#开启session统计功能
spring.datasource.druid.web-stat-filter.session-stat-enable=true
#缺省sessionStatMaxCount是1000个
spring.datasource.druid.web-stat-filter.session-stat-max-count=1000
#spring.datasource.druid.web-stat-filter.principal-session-name=
#spring.datasource.druid.web-stat-filter.principal-cookie-name=
#spring.datasource.druid.web-stat-filter.profile-enable=

##### StatViewServlet配置 #######
#启用内置的监控页面
spring.datasource.druid.stat-view-servlet.enabled=true
#内置监控页面的地址
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
#关闭 Reset All 功能
spring.datasource.druid.stat-view-servlet.reset-enable=false
#设置登录用户名
spring.datasource.druid.stat-view-servlet.login-username=admin
#设置登录密码
spring.datasource.druid.stat-view-servlet.login-password=123
#白名单(如果allow没有配置或者为空,则允许所有访问)
spring.datasource.druid.stat-view-servlet.allow=127.0.0.1
#黑名单(deny优先于allow,如果在deny列表中,就算在allow列表中,也会被拒绝)
spring.datasource.druid.stat-view-servlet.deny=

3,访问监控页面

(1)启动项目后我们随便请求几个 contoller 接口,然后访问 /druid 地址打开监控页面,输入用户名密码后登录:
 
(2)“数据源”子页面里是当前 DataSource 的基本信息统计。注意“filter类名”不能为空,否则会有一些信息无法统计(如“SQL 监控”会无法获取 JDBC 相关的 SQL 执行信息)

(3)“SQL 监控”子页面则统计了所有 SQL 语句的执行情况:

(4)“URI 监控”子页面则统计所有 controller 接口访问以及执行情况:

附一:慢 SQL 记录

(1)有时系统会存在一些 SQL 执行很慢,如果希望日志记录下来,可以添加如下配置开启 Druid 的慢 SQL 记录功能。
注意slow-sql-millis 用来配置 SQL 慢的标准,执行时间超过 slow-sql-millis 的就是慢。slow-sql-millis 的缺省值为 3000,也就是 3 秒。
# 开启慢SQL统计(这里超过10毫秒则判定为慢SQL)
spring.datasource.druid.filter.stat.enabled=true
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=10

(2)启用后如果遇到执行很慢的 SQL,便会输出到日志中,方便我们定位分析。

附二:Spring 监控

(1)默认情况下监控控制台中“Spring监控”子页面内容是空的,我们可以通过类似如下的配置,利用 aop 对各个内容接口的执行时间、jdbc 数进行记录。
# Spring 监控配置(配置多个AOP切入点使用英文逗号分隔)
spring.datasource.druid.aop-patterns=com.example.hanggetest2.dao.*

(2)同时记得修改 pom.xml 文件,添加 spring-boot-starter-aop 依赖以提供 AOP 支持:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

(3)启动项目后我们随便请求几个 contoller 接口,然后访问“Spring监控”即可查看方法执行的次数、执行的时间等信息。

附三:获取 Druid 的监控数据

    Druid 的监控数据可以在开启 StatFilter 后通过 DruidStatManagerFacade 进行获取,获取到监控数据之后我们便可以将其暴露给我们自己的监控系统进行使用。Druid 默认的监控系统数据也来源于此。

(1)下面是一个简单的演示样例,在 Spring Boot 中通过 HTTP 接口将 Druid 监控数据以 JSON 的形式暴露出去(实际使用中我们可以根据实际的需要自由地对监控数据、暴露方式进行扩展)
@RestController
public class DruidStatController {
    @GetMapping("/druid-stat")
    public Object druidStat(){
        // DruidStatManagerFacade#getDataSourceStatDataList 该方法可以获取所有数据源的监控数据
        // 除此之外 DruidStatManagerFacade 还提供了一些其他方法,我们可以按需选择使用。
        return DruidStatManagerFacade.getInstance().getDataSourceStatDataList();
    }
}

(2)我们通过 /druid-stat 接口获取到如下统计数据:

附四:去除广告

(1)默认情况下,监控页面的底部会有一个阿里的广告:

(2)如果需要将其去除的话,在 SpringBoot 项目中编写一个 RemoveDruidAdConfig 配置类即可,代码如下:
原理说明:之所以底部有广告,是因为其引入的 druid jar 包的 common.js 中的内容(里面有一段是在 footer 添加广告),在 RemoveDruidAdConfig 配置类中使用过滤器过滤 common.js 的请求,重新处理后用正则替换相关的广告代码片段.
@Configuration
@ConditionalOnWebApplication
@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled",
        havingValue = "true", matchIfMissing = true)
public class RemoveDruidAdConfig {

    /**
     * 方法名: removeDruidAdFilterRegistrationBean
     * 方法描述:  除去页面底部的广告
     * @param properties
     * @return org.springframework.boot.web.servlet.FilterRegistrationBean
     * @throws
     */
    @Bean
    public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties)
    {
        // 获取web监控页面的参数
        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
        // 提取common.js的配置路径
        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");

        final String filePath = "support/http/resources/js/common.js";

        //创建filter进行过滤
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
            }

            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                chain.doFilter(request, response);
                // 重置缓冲区,响应头不会被重置
                response.resetBuffer();
                // 获取common.js
                String text = Utils.readFromResource(filePath);
                // 正则替换banner, 除去底部的广告信息
                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
                text = text.replaceAll("powered.*?shrek.wang</a>", "");
                response.getWriter().write(text);
            }

            @Override
            public void destroy() {
            }
        };
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns(commonJsPattern);
        return registrationBean;
    }
}
评论0