五整合数据库连接池Druid

一、资源池

  • 一种设计模式,系统初始化的时候创建一组资源,放到一个池子里。需要的时候从资源池里面选一个出来工作,用完了放回去,而不是随时创建和销毁。

  • 资源的创建与销毁都是比较耗时的,资源池有效避免了频繁创建和销毁资源的消耗问题,能有效的提高程序的性能,常见的资源池有线程池,内存池,java对象池以及数据库连接池等。

二、数据库连接池

  • 负责分配、管理和释放数据库连接的资源池,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

  • 可以通过设置数据库连接池的最大连接数来防止系统过量连接数据库,并根据数据库连接池的管理机制监视数据库连接

三、Druid

目前市面上主流的数据库连接池主要是C3P0,DBCP,BoneCP及Druid等

其中,Druid是Java语言中最好的数据库连接池,且能提供强大的监控及扩展功能,是阿里巴巴开发的号称为监控而生的数据库连接池!  Druid具备以下功能:

  1. 充当数据库连接池
  2. 监控数据库/网络访问性能
  3. 获得SQL执行日志

四、实践整合Druid

创建一个新的项目spring-cloud-druid

第一步:引入依赖:druid-spring-boot-starter

引入父工程,我们最开始创建的工程,在文章最下面有下载连接

    <parent>
        <artifactId>com.springcloud</artifactId>
        <groupId>com.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

引入druid依赖,完整的pom如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>com.springcloud</artifactId>
        <groupId>com.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.druid</groupId>
    <artifactId>spring-cloud-druid</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--eureka 客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--作为web项目存在-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--配置客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>

        <!--实时刷新配置文件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <!--mysql 驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <!--spring boot 提供的jdbc支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--druid对spring监控需要的aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

    <!-- 添加spring-boot的maven插件,不能少,打jar包时得用 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

第二步:加配置,在config配置中心的configs目录下添加datasource-dev.yml文件,专门配置统一数据库信息

spring:
  # 配置数据库信息
  datasource:
    # 数据源配置
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1:3306/spring?serverTimezone=GMT%2B8&characterEncoding=UTF-8&useSSL=false  # 设置时区
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource   # 指定数据源为druid
    # 数据库连接池配置
    druid:
      # 初始化 最小 最大
      initial-size: 5
      min-idle: 5
      max-active: 20
      # 配置获取连接等待超时的时间
      max-wait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      time-between-eviction-runs-millis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      # 打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      # 配置多个英文逗号分隔
      filters: stat,wall

第三步:在启动springcloud-client模块时初始化数据库连接,所以应该在springcloud-client模块的配置文件指向datasource配置文件

server:
  port: 8666 #服务端口
spring:
  profiles:
    active: dev #当前生效环境
  application:
    name: spring-cloud-druid #指定应用的唯一标识/服务名
  # 配置中心
  cloud:
    config:
      fail-fast: true
      name: ${spring.application.name},datasource,springcloud-client #指定工程于config server中的应用名(此处包括datasource,届时启动初始化环境会包含datasource-{spring.profiles.active}.yml文件)
      profile: ${spring.profiles.active} #指定工程于config server中的生效环境
      uri: http://localhost:8080 #指定配置中心的注册路径
 # 注册中心配置
eureka:
  instance:
    prefer-ip-address: true #优先使用IP地址注册
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/ #eureka的注册地址 

第四步:启动springcloud-client模块,验证数据库是否配置成功,部分启动日志如下:

在这里插入图片描述 可以看到,当限定dev环境下启动springcloud-client模块时,同时读取的是springcloud-client-dev.yml及datasource-dev.yml文件的内容进行初始化,其中的{dataSource-1} inited 表示数据库初始化完成,也就是数据库连接成功

至此,数据库连接池Druid与Spring Boot/Spring Cloud的基本整合完成。

五、整合实现Druid的SQL监控

Druid的监控功能主要围绕StatFilter展开,包含SQL执行监控,Web关联监控以及Spring关联监控等功能。

1、配置视图Servlet—–StatViewServlet

Druid内置提供了一个StatViewServlet用于展示Druid的统计信息,这个StatViewServlet的用途包括:

  • 提供监控信息展示的html页面
  • 提供监控信息的JSON API
package com.druid.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @类名 DruidConfiguration
 * @描述 sql 监控
 * @版本 1.0
 * @创建人 XuKang
 * @创建时间 2021/6/18 15:33
 **/
@Configuration
public class DruidConfiguration {
    /**
     * 注册Servlet信息, 配置监控视图(由于yml文件无法直接设置loginUsername和loginPassword属性,故使用java配置的方式)
     */
    @Bean
    public ServletRegistrationBean druidServlet() {

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        //stat视图设置
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        Map<String, String> initParameters = new HashMap();
        initParameters.put("loginUsername", "admin"); // 用户名
        initParameters.put("loginPassword", "admin"); // 密码
        initParameters.put("resetEnable", "false"); // 禁用HTML页面上的“Reset All”功能
        initParameters.put("allow", ""); // IP白名单 (没有配置或者为空,则允许所有访问)
        //initParameters.put("deny", "192.168.20.38");// IP黑名单 (存在共同时,deny优先于allow),如果满足deny的话提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;
    }
}

访问localhost:配置模块的端口号/druid/login.html(默认8080端口),使用上述配置中的登录名及登录密码进行登录 在这里插入图片描述 看到监控页面的主页:其包含数据库信息,SQL监控,SQL防火墙,Web应用,URI监控,Session监控以及Spring监控以及Druid提供的JSON API等栏目 在这里插入图片描述 在数据库信息栏目中可以清晰看到关于数据库的相关配置信息

在这里插入图片描述

在SQL监控栏目可以看到系统执行SQL的具体情况(本项目在启动初始化数据库时会自动执行 “SELECT ‘x’ ”的SQL语句)

在这里插入图片描述

2、配置SQL防火墙过滤器—WallFilter

Druid携带一个防火墙过滤器,有效控制系统内SQL的执行权限,禁止非法SQL行为

package com.druid.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @类名 DruidConfiguration
 * @描述 sql 监控
 * @版本 1.0
 * @创建人 XuKang
 * @创建时间 2021/6/18 15:33
 **/
@Configuration
public class DruidConfiguration {
    /**
     * 注册Servlet信息, 配置监控视图(由于yml文件无法直接设置loginUsername和loginPassword属性,故使用java配置的方式)
     */
    @Bean
    public ServletRegistrationBean druidServlet() {

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        //stat视图设置
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        Map<String, String> initParameters = new HashMap();
        initParameters.put("loginUsername", "admin"); // 用户名
        initParameters.put("loginPassword", "admin"); // 密码
        initParameters.put("resetEnable", "false"); // 禁用HTML页面上的“Reset All”功能
        initParameters.put("allow", ""); // IP白名单 (没有配置或者为空,则允许所有访问)
        //initParameters.put("deny", "192.168.20.38");// IP黑名单 (存在共同时,deny优先于allow),如果满足deny的话提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;
    }

    @Bean(name = "wallFilter")
    public WallFilter wallFilter() {
        WallConfig wallConfig = new WallConfig();
        wallConfig.setDeleteWhereNoneCheck(true);

        wallConfig.setMultiStatementAllow(true); //允许sql批量操作
        wallConfig.setNoneBaseStatementAllow(true);//允许非基本语句的其他语句
        WallFilter wallfilter = new WallFilter();
        wallfilter.setConfig(wallConfig);

        return wallfilter;
    }

}

我们可以看到SQL防火墙栏目记录了防火墙对SQL调用的统计指数 在这里插入图片描述

3、配置Web关联监控—-webStatFilter

监控web请求

package com.druid.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @类名 DruidConfiguration
 * @描述 sql 监控
 * @版本 1.0
 * @创建人 XuKang
 * @创建时间 2021/6/18 15:33
 **/
@Configuration
public class DruidConfiguration {
    /**
     * 注册Servlet信息, 配置监控视图(由于yml文件无法直接设置loginUsername和loginPassword属性,故使用java配置的方式)
     */
    @Bean
    public ServletRegistrationBean druidServlet() {

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        //stat视图设置
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        Map<String, String> initParameters = new HashMap();
        initParameters.put("loginUsername", "admin"); // 用户名
        initParameters.put("loginPassword", "admin"); // 密码
        initParameters.put("resetEnable", "false"); // 禁用HTML页面上的“Reset All”功能
        initParameters.put("allow", ""); // IP白名单 (没有配置或者为空,则允许所有访问)
        //initParameters.put("deny", "192.168.20.38");// IP黑名单 (存在共同时,deny优先于allow),如果满足deny的话提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;
    }

    @Bean(name = "wallFilter")
    public WallFilter wallFilter() {
        WallConfig wallConfig = new WallConfig();
        wallConfig.setDeleteWhereNoneCheck(true);

        wallConfig.setMultiStatementAllow(true); //允许sql批量操作
        wallConfig.setNoneBaseStatementAllow(true);//允许非基本语句的其他语句
        WallFilter wallfilter = new WallFilter();
        wallfilter.setConfig(wallConfig);

        return wallfilter;
    }

    /**
     * 注册Filter信息, 监控拦截器
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        WebStatFilter webStatFilter = new WebStatFilter();
        webStatFilter.setProfileEnable(true); //开启
        webStatFilter.setSessionStatEnable(true);
        filterRegistrationBean.setFilter(webStatFilter);
        filterRegistrationBean.addUrlPatterns("/*");
        Map<String, String> initParameters = new HashMap();
        initParameters.put("sessionStatMaxCount", "1000");
        initParameters.put("principalCookieName", "USER_COOKIE");
        initParameters.put("principalSessionName", "USER_SESSION");
        initParameters.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.setInitParameters(initParameters);
        return filterRegistrationBean;
    }
}

请求访问Client的getName接口 在这里插入图片描述 再去查看URI监控栏目信息,可以看到Druid的监控可以记录对系统的URI请求 在这里插入图片描述

4、配置Spring关联监控—-DruidSpringConfiguration

相当于创建切面对Spring请求的controller等进行监控

package com.druid.config;

import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * @类名 DruidSpringConfiguration
 * @描述 TODO
 * @版本 1.0
 * @创建人 XuKang
 * @创建时间 2021/6/21 9:20
 **/
@Aspect //相当于做了一个AOP
@Configuration
public class DruidSpringConfiguration {
    /**
     * 拦截器
     * @return
     */
    @Bean
    public DruidStatInterceptor druidStatInterceptor() {
        return new DruidStatInterceptor();
    }
    /**
     * 切点
     * @return
     */
    @Bean
    @Scope("prototype")
    public JdkRegexpMethodPointcut druidStatPointcut() {
        JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
        //指明需要监控的类
        jdkRegexpMethodPointcut.setPatterns("com.druid.controller.*");
        return jdkRegexpMethodPointcut;
    }
    /**
     * 通知
     * @return
     */
    @Bean
    public Advisor druidAdviceAdvisor() {
        DefaultBeanFactoryPointcutAdvisor defaultBeanFactoryPointcutAdvisor = new DefaultBeanFactoryPointcutAdvisor();
        defaultBeanFactoryPointcutAdvisor.setAdvice(druidStatInterceptor());
        defaultBeanFactoryPointcutAdvisor.setPointcut(druidStatPointcut());
        return defaultBeanFactoryPointcutAdvisor;
    }
}

在这里插入图片描述 一样去请求访问Client模块的getName接口,然后打开Spring监控模块,可以看到Druid监控具体到了Spring系统中的类接口访问的详细信息

六、总结

  1. 数据库连接池负责分配、管理和释放数据库连接的资源池,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
  2. Druid是Java语言中最好的数据库连接池,其具备数据库连接管理、监控数据库/网络访问性能等功能特性
  3. 整合Druid数据库连接池需要引入依赖 druid-spring-boot-starter ,并配置相关属性

七、资源地址

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/4499.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!