Spring Boot 整合 Druid自定义数据源

  • Druid简介
  • Druid功能
  • 配置参数表
  • Druid引入到Web项目
  • 配置Druid参数和连接池实现
  • 实现对SQL,Spring,url等监控
  • Durid连接池及Filter监控实现效果



)

Druid简介

Durid是是阿里巴巴开源平台上一个数据库连接池的实现,结合了 C3P0、DBCP、PROXOOL 等 DB 池的优点,同时加入了日志监控,可以实时监控数据库访问性能,对于线上分析数据库访问性能有很大的帮助。现在Spring Boot2.0以上都是默认使用Hikari 数据源,可以说Druid和Hikarl都是目前Java Web上最优秀的数据源。Druid具有数据吞吐量大,支持流式数据摄入和实时,查询灵活且快,社区支持力度大等几大优点。

Druid功能

1、替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。

2、可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。

3、数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。

4、SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。

5、扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。

配置参数表

参数作用

配置

缺省值

作用

driverClassName

这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)

jdbcUrl

连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2
oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto

name

配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:“DataSource-” + System.identityHashCode(this)

username

连接数据库的用户名

password

连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter

driverClassName

这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置)

initialSize

0

初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时

maxActive

8

最大连接池数量

maxIdle

8

已经不再使用,配置了也没效果

minIdle

最小连接池数量

maxWait

获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。

poolPreparedStatements

false

是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。

maxPoolPreparedStatementPerConnectionSize

-1

要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100

validationQuery

用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。

testOnBorrow

true

申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。

testOnReturn

false

归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能

testWhileIdle

false

建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。

keepAlive

false

(1.0.28) 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。

timeBetweenEvictionRunsMillis

1分钟(1.0.14)

有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明

numTestsPerEvictionRun

不再使用,一个DruidDataSource只支持一个EvictionRun

minEvictableIdleTimeMillis

连接保持空闲而不被驱逐的最小时间

connectionInitSqls

物理连接初始化的时候执行的sql

exceptionSorter

根据dbType自动识别

当数据库抛出一些不可恢复的异常时,抛弃连接

filters

属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall

proxyFilters

类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

Druid引入到Web项目

  • 首先需要在自己Web项目的pom文件中引入Druid数据源依赖,这个依赖可以在Maven官网中的Maven Repository获取。
  • 我这里用的是1.1.9的版本,想用可以直接复制。
<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
      </dependency>
    <!-- spring默认使用yml中的配置,但有时候要用传统的xml或properties配置,就需要使用spring-boot-configuration-processor了 -->
      <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-configuration-processor</artifactId>
      	<optional>true</optional>
      </dependency>

配置Druid参数和连接池实现

  • 下面是我的Web项目properties文件参数的配置,里面的参数释义参照上面的表格即可。
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
spring.datasource.druid.username=root
spring.datasource.druid.password=hello
spring.datasource.druid.initial-size=1
spring.datasource.druid.max-active=50
spring.datasource.druid.max-wait=60000
spring.datasource.druid.max-idle=10
spring.datasource.druid.min-idle=1
spring.datasource.druid.pool-prepared-statements=false
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=100
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.filters=stat,wall,log4j
spring.datasource.druid.min-evictable-idle-time-millis=300000
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录  
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  • 这个下面是DruidDataSource配置类的具体代码可直接复制使用,Druid核心就是注入DruidDataSource,方法中赋值的所有参数跟properties文件中的是对应的。这里我采取的是用@value方式给类里面的参数赋值。也可以建一个实体类来给里面的参数赋值,采用@ConfigurationProperties(prefix = “spring.druid.datasource”)的方式给里面的属性赋值,对于@ConfigurationProperties 绑定配置文件参数不熟悉时,可以参考此人写的Spring Boot 全局配置文件,看个人喜好,这个地方可扩展性很强。
  • 其中用到了@Primary注解,在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary 的作用就出来了
/**
 * 
 */
package com.xb.config;

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.alibaba.druid.pool.DruidDataSource;

/**
 * @author XWJ 2019年10月9日
 */
@Configuration // 此注解用于定义配置类,可以替换xml文件
public class DruidDataSourceConfig {

	@Value("${spring.datasource.druid.driver-class-name}")
	private String driverClassName;

	@Value("${spring.datasource.druid.url}")
	private String url;

	@Value("${spring.datasource.druid.username}")
	private String username;

	@Value("${spring.datasource.druid.password}")
	private String password;

	@Value("${spring.datasource.druid.initial-size}")
	private int initialSize;

	@Value("${spring.datasource.druid.max-active}")
	private int maxActive;

	@Value("${spring.datasource.druid.max-wait}")
	private int maxWait;

	@Value("${spring.datasource.druid.max-idle}")
	private int minIdle;

	@Value("${spring.datasource.druid.pool-prepared-statements}")
	private boolean poolPreparedStatements;

	@Value("${spring.datasource.druid.max-pool-prepared-statement-per-connection-size}")
	private int maxPoolPreparedStatementPerConnectionSize;

	@Value("${spring.datasource.druid.validation-query}")
	private String validationQuery;

	@Value("${spring.datasource.druid.test-on-borrow}")
	private boolean testOnBorrow;

	@Value("${spring.datasource.druid.test-on-return}")
	private boolean testOnReturn;

	@Value("${spring.datasource.druid.test-while-idle}")
	private boolean testWhileIdle;

	@Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
	private int timeBetweenEvictionRunsMillis;
	
	@Value("${spring.datasource.druid.filters}")
	private String filters;

	@Value("${spring.datasource.druid.min-evictable-idle-time-millis}")
	private int minEvictableIdleTimeMillis;
	
	@Value("${spring.datasource.druid.connection-properties}")
	private String connectionProperties;

	@Bean
	@Primary
	public DruidDataSource  dataSource() throws SQLException {
		//@Primary 注解作用是当程序选择dataSource时选择被注解的这个
		DruidDataSource dds=new DruidDataSource();
		dds.setDriverClassName(driverClassName);
		dds.setUrl(url);
		dds.setUsername(username);
		dds.setPassword(password);
		dds.setInitialSize(initialSize);
		dds.setMaxActive(maxActive);
		dds.setMaxWait(maxWait);
		dds.setMinIdle(minIdle);
		dds.setPoolPreparedStatements(poolPreparedStatements);
	    dds.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
		dds.setValidationQuery(validationQuery);
		dds.setTestOnBorrow(testOnBorrow);
		dds.setTestOnReturn(testOnReturn);
		dds.setTestWhileIdle(testWhileIdle);
		dds.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
		dds.setFilters(filters);
		dds.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
		dds.setConnectionProperties(connectionProperties);
		System.out.println("***************************************");
		System.out.println("*                                     *");
		System.out.println("*============Druid连接池已启用 ============*");
		System.out.println("*                                     *");
		System.out.println("***************************************");
		return dds;
	}
}

实现对SQL,Spring,url等监控

  • 1.配置ServletRegistrationBean
    Spring Boot默认是不支持Servlert的,尤其是Druid连接池,想要保留对SQLl的监控,那么就迫切需要Spring Boot来支持Servlet,由于Spring Boot是以jar包的形式启动嵌入式的Servlet容器来启动Spring Boot应用,所以没有web.xml,想要使用servlet的功能只能注入Spring Boot提供的ServletRegistrationBean接口。
  • FilterRegistrationBean
    Filter是Servlet中最实用的技术,它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,上面已经添加了Servlet,这个地方同理也需要对FilterRegistrationBean进行注入。
  • 下面是实现Druid监控的配置类☆☆☆☆☆
/**
 * 
 */
package com.xb.config;
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 com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
 
/**
 * Druid 配置类
 * @author xwj
 * 2018-09-04
 */
@SuppressWarnings("all")
@Configuration
public class DruidMonitoringConfig {
 
    /**
     * 配置监控服务器
     *
     * @return 返回监控注册的servlet对象
     */   
	@Bean
    public ServletRegistrationBean statViewServletDemo() {
        ServletRegistrationBean srb = new ServletRegistrationBean(new StatViewServlet());
        srb.addUrlMappings("/druid/*");
        // 添加IP白名单
        srb.addInitParameter("allow", "127.0.0.1");
        // 添加IP黑名单,当白名单和黑名单重复时,黑名单优先级更高
        srb.addInitParameter("deny", "192.168.25.123");
        // 添加控制台管理用户
        srb.addInitParameter("loginUsername", "xwj");
        srb.addInitParameter("loginPassword", "123");
        // 是否能够重置数据
        srb.addInitParameter("resetEnable", "true");
        return srb;
    }
    /**
     * 配置服务过滤器
     *
     * @return 返回过滤器配置对象
     */
    @Bean
    public FilterRegistrationBean statFilterDemo() {
        FilterRegistrationBean frb = new FilterRegistrationBean(new WebStatFilter());
        // 添加过滤规则
        frb.addUrlPatterns("/*");
        // 忽略过滤格式
        frb.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,");
        return frb;
    }
}

Durid连接池及Filter监控实现效果

  • 上面的都配置完成以后,可以看一下实现效果,从图中就可以看出,连接池配置成功了。
  • 然后再看一下Filter监控配置的怎么样,再浏览器中输入URLhttp://127.0.0.1:8086/druid/login.html出现如下界面,输入在ServletRegistrationBean
  • 访问成功以后就会登录Druid Monitor监控管理界面,在里面可以看到对sql,Spring,url,session等的监控情况,
  • OK,写到这里一个完成的Druid数据库连接池就完成了,该连接池可以实现对Web应用的性能进行统计监控
    上述代码个人亲测实用,如有错误还请指出,最后看都看了,码字不易,留个赞再走吧!!!!