今天,日月在这里教大家如何使用springboot集成druid-Monitor进行sql监控、数据源监控,sql慢查询监控等。还是先套用一波网上的官方话语。。。

Druid

Druid:一款为监控而生的数据库连接池框架,整个项目由数据库连接池、插件框架和SQL解析器组成。
Druid功能介于PowerDrill和Dremel之间,它几乎实现了Dremel的所有功能,并且从PowerDrill吸收一些有趣的数据格式。Druid允许以类似Dremel和PowerDrill的方式进行单表查询,同时还增加了一些新特性,如为局部嵌套数据结构提供列式存储格式、为快速过滤做索引、实时摄取和查询、高容错的分布式体系架构等。

Spring Boot

spring框架作为JavaEE框架领域的一款重要的开源框架,在企业应用开发中有着很重要的作用,同时Spring框架及其子框架很多,所以知识量很广。
Spring Boot:一款Spring框架的子框架,也可以叫微框架,是2014年推出的一款使Spring框架开发变得容易的框架。学过Spring框架的都知识,Spring框架难以避免地需要配置不少XMl,而使用Spring Boot框架的话,就可以使用注解开发,极大地简化基于Spring框架的开发。Spring Boot充分利用了JavaConfig的配置模式以及“约定优于配置”的理念,能够极大的简化基于Spring MVC的Web应用和REST服务开发。

依然,我们还是在上一章项目 springBoot集成redis 的基础上进行集成

1、配置中心新增Druid配置

#master 数据源配置
master.datasource.url=jdbc:mysql://localhost:3306/test3?useSSL=false&useUnicode=true&characterEncoding=utf8
master.datasource.username=root
master.datasource.password=123456
master.datasource.maxActive=50
master.datasource.maxWait=60000
master.datasource.driverClassName=com.mysql.jdbc.Driver
 
#cluster 数据源配置
cluster.datasource.url=jdbc:mysql://localhost:3306/test4?useSSL=false&useUnicode=true&characterEncoding=utf8
cluster.datasource.username=root
cluster.datasource.password=123456
cluster.datasource.maxActive=50
cluster.datasource.maxWait=60000
cluster.datasource.driverClassName=com.mysql.jdbc.Driver

spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=30000

#打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

2、新增数据源dataSource的配置
master 数据源

import java.sql.SQLException;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
@RefreshScope
@Configuration
// 扫描 Mapper 接口并容器管理
@MapperScan(basePackages = MasterDataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfiguration {
    // 精确到 master 目录,以便跟其他数据源隔离
    static final String PACKAGE = "com.chenqi.springboot.dao.master";
    static final String MAPPER_LOCATION = "classpath:mapper/master/*.xml";
    @Value("${master.datasource.url}")
    private String url;
    @Value("${master.datasource.username}")
    private String user;
    @Value("${master.datasource.password}")
    private String password;
    
    @Value("${master.datasource.maxActive}")
    private Integer maxActive;
    
    @Value("${master.datasource.maxWait}")
    private Integer maxWait;
    @Value("${master.datasource.driverClassName}")
    private String driverClass;
    
    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;
    
    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private Integer maxPoolPreparedStatementPerConnectionSize;
    
    @Value("${spring.datasource.filters}")
    private String filters;
    
    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;
    @ConfigurationProperties(prefix="spring.datasource")
    @RefreshScope
    @Bean(name = "dataSource")
    @Primary
    public DruidDataSource masterDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        dataSource.setMaxActive(maxActive);
        dataSource.setMaxWait(maxWait);
        dataSource.setSharePreparedStatements(poolPreparedStatements);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        dataSource.setConnectionProperties(connectionProperties);
        try {
            dataSource.setFilters(filters);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return dataSource;
    }
    @RefreshScope
    @Bean(name = "masterTransactionManager")
    @Primary
    public DataSourceTransactionManager masterTransactionManager() {
        return new DataSourceTransactionManager(masterDataSource());
    }
    @RefreshScope
    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("dataSource") DruidDataSource masterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(masterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(MasterDataSourceConfiguration.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}

cluster 数据源

import java.sql.SQLException;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
@RefreshScope
@Configuration
//扫描 Mapper 接口并容器管理
@MapperScan(basePackages = ClusterDataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = "clusterSqlSessionFactory")
public class ClusterDataSourceConfiguration {
    
    // 精确到 cluster 目录,以便跟其他数据源隔离
    static final String PACKAGE = "com.chenqi.springboot.dao.cluster";
    static final String MAPPER_LOCATION = "classpath:mapper/cluster/*.xml";
    @Value("${cluster.datasource.url}")
    private String url;
    @Value("${cluster.datasource.username}")
    private String user;
    @Value("${cluster.datasource.password}")
    private String password;
    
    @Value("${cluster.datasource.maxActive}")
    private Integer maxActive;
    
    @Value("${cluster.datasource.maxWait}")
    private Integer maxWait;
    @Value("${cluster.datasource.driverClassName}")
    private String driverClass;
    
    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;
    
    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private Integer maxPoolPreparedStatementPerConnectionSize;
    
    @Value("${spring.datasource.filters}")
    private String filters;
    
    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;
    @ConfigurationProperties(prefix="spring.datasource")
    @RefreshScope
    @Bean(name = "clusterDataSource")
    public DruidDataSource clusterDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        dataSource.setMaxActive(maxActive);
        dataSource.setMaxWait(maxWait);
        dataSource.setSharePreparedStatements(poolPreparedStatements);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        dataSource.setConnectionProperties(connectionProperties);
        try {
            dataSource.setFilters(filters);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return dataSource;
    }
    @RefreshScope
    @Bean(name = "clusterTransactionManager")
    public DataSourceTransactionManager clusterTransactionManager() {
        return new DataSourceTransactionManager(clusterDataSource());
    }
    @RefreshScope
    @Bean(name = "clusterSqlSessionFactory")
    public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("clusterDataSource") DruidDataSource clusterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(clusterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(ClusterDataSourceConfiguration.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}

3、添加servlet 和 filter

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import com.alibaba.druid.support.http.StatViewServlet;
@SuppressWarnings("serial")
@WebServlet(urlPatterns = "/druid/*",
        initParams={
                @WebInitParam(name="allow",value="127.0.0.1"),// IP白名单 (没有配置或者为空,则允许所有访问,可配置多个)
                //@WebInitParam(name="deny",value="192.168.16.111"),// IP黑名单 (存在共同时,deny优先于allow)
                @WebInitParam(name="loginUsername",value="admin"),// 用户名
                @WebInitParam(name="loginPassword",value="123456"),// 密码
                @WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能
        })
public class DruidStatViewServlet extends StatViewServlet {
}

DruidStatFilter.java

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import com.alibaba.druid.support.http.WebStatFilter;
@WebFilter(filterName="druidStatFilter",urlPatterns="/*",
initParams={
        // 忽略资源
        @WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")
})
public class DruidStatFilter extends WebStatFilter {
}

4、启动类添加servlet扫描

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
@ServletComponentScan(value = "com.chenqi.springboot.config.servlet")//servlet的扫描
public class SpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

仅仅只需要这四步,就完成了,OK,我们先将上章reids的代码注释掉,方便测试

import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.chenqi.springboot.redis.RedisUtils;
import com.chenqi.springboot.service.TestService;
@RestController
public class SpringBootController {
    
    public static final Logger log = LoggerFactory.getLogger(SpringBootController.class);
    
    @Autowired
    TestService testService;
    
    @Autowired
    private RedisUtils redisUtils;
    @RequestMapping(value = "/hello/{id}")
    public String hello(@PathVariable(value = "id") String id){
        //查询缓存中是否存在
        boolean hasKey = redisUtils.exists(id);
        String str = "";
        /*if(hasKey){
            //获取缓存
            Object object =  redisUtils.get(id);
            log.info("从缓存获取的数据"+ object);
            str = object.toString();
        }else{
            //从数据库中获取信息
            log.info("从数据库中获取数据");
            str = testService.test();
            //数据插入缓存(set中的参数含义:key值,user对象,缓存存在时间10(long类型),时间单位)
            redisUtils.set(id,str,10L,TimeUnit.MINUTES);
            log.info("数据插入缓存" + str);
        }*/
        
        str = testService.test();
        return str;
    }
}

依次启动spring-cloud-eureka、spring-cloud-config-server、springboot

访问:http://localhost:8002/druid/index.html

druid 监控页面 看哪些指标_sql监控

使用我们在DruidStatViewServlet中配置的用户名密码进行登录

druid 监控页面 看哪些指标_druid 监控页面 看哪些指标_02

druid 监控页面 看哪些指标_springBoot_03

druid 监控页面 看哪些指标_druid Monitor_04


这个时候,因为还没有请求,所以数据源和sql监控页面都是空的

OK,我们发生一个查询请求:http://localhost:8002/hello/111

druid 监控页面 看哪些指标_java_05

再次刷新druid-Monitor中的数据源窗口和sql监控窗口

druid 监控页面 看哪些指标_java_06

druid 监控页面 看哪些指标_druid 监控页面 看哪些指标_07

druid 监控页面 看哪些指标_java_08

可以发现,我们配置的两个数据源和两条查询sql都已经被监控到了,至此,springboot集成druid-Monitor就完成了