从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

    • SpringBoot 教程-尚硅谷

      • SpringBoot 课程介绍
      • Spring 和 SpringBoot
      • HelloWorld
      • 了解自动配置原理
      • 底层注解-@Configuration 详解
      • 底层注解-@Import 导入组件
      • 底层注解-@Conditional 条件装配
      • 原生配置文件引入-@ImportResource
      • 底层注解-配置绑定 @ConfigurationProperties
      • 自动配置原理
      • 自动配置流程
      • Lombok 简化开发
      • DevTools
      • Spring-Initailizr
      • 配置文件-Yaml 用法
      • Web 开发简介
      • web 开发-静态资源规则于定制化
      • 静态资源配置原理
      • Rest 映射及源码解析
      • 请求映射原理
      • 常用参数注解使用
      • MatrixVariable:矩阵变量
      • 各种类型参数解析原理
      • Servlet-API 参数解析原理
      • Model、Map 参数解析原理
      • 自定义对象参数绑定原理
      • 自定义 Converter 原理
      • 数据响应原理
      • 内容协商原理
      • 基于请求参数的内容原理
      • 自定义 MessageConverter 原理
      • Thymeleaf 初体验
      • web 实验-后台管理系统
      • web 实验-抽取公共页面
      • web 实验-遍历数据
      • 源码分析-视图解析器与视图
      • 拦截器-登录检查与静态资源放行
      • 拦截器的执行时机和原理
      • 单文件和多文件上传的使用
      • 文件上传原理
      • 错误处理机制
      • 错误处理-底层组件源码分析
      • 异常处理流程
      • 几种异常处理原理
      • Web 原生对象注入
      • 嵌入式 Servlet 容器
      • 定制化原理
      • 数据库场景的自动配置分析和整合测试
      • 自定义方式整合 Druid
        • 自定义使用
        • 配置监控页
        • 设置登录
        • 1.2 配置监控页面访问密码
        • SQL 监控
        • 3.7 区间分布
        • 监控 web 应用
        • SQL 注入(防火墙)
        • 简化配置
        • 最后
      • 通过 starter 整合 Druid
      • 整合 Mybatis
      • 使用注解整合 Mybatis
      • 整合 MybatisPlus 操作数据库
      • MybatisPlus-列表分页展示
      • 整合 Redis
      • 单元测试-Junit5
      • 单元测试-断言机制
      • 单元测试-前置条件
      • 单元测试-嵌套测试
      • 单元测试-参数化测试
      • 指标监控-基本概念
      • 指标监控-配置 EndPoint
      • 指标监控-可视化
      • 原理解析-Profile 功能
      • 配置文件深入
      • 自定义 Starter
      • SpringApplication 初始化过程
      • SpringBoot 完整启动过程
  • Java
  • SpringBoot
  • SpringBoot 教程-尚硅谷
2023-08-22
目录

自定义方式整合 Druid

# 490.自定义方式整合 Druid

默认情况下,使用的是 HikariDataSource,该框架性能也是不错的,但国内更常用的是 Druid,本篇来讲讲如何在 SpringBoot 中使用 Druid,因为它对有很完善的解决方案,例如有监控、防 SQL 注入攻击等功能

Druid 是开源的,托管在 GitHub (opens new window) 上。并且有很详细的中文文档:

在 SpringBoot 中,要使用第三方技术,要么是自定义,要么找有无相关的 starter,我们先看看自定义的情况下怎么用; ‍

# 自定义使用

‍ 我们先引入依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>
1
2
3
4
5

‍ 然后我们新增一个配置类,用来注入 DataSource 对象:

package com.peterjxl.learnspringbootwebadmin.config;


import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class MyDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new DruidDataSource();
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

‍ 注意,由于我们已经在配置文件中,配置了数据源链接信息,因此可以通过配置绑定的方式,来完成 Druid 数据源的配置。

然后就会使用我们的 Druid 数据源了。这是因为在配置类 DataSourceConfiguration 中,如果容器中有数据源了,那么根据条件装配,Hikari 就不会被放入容器中:

@ConditionalOnMissingBean(DataSource.class)
static class Hikari {
1
2

‍ 接下来我们测试下,打印下容器中的数据源类型:

package com.peterjxl.learnspringbootwebadmin;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Slf4j
@SpringBootTest
class LearnSpringBootWebAdminApplicationTests {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() {
        Long aLong = jdbcTemplate.queryForObject("select count(*) from students", Long.class);
        log.info("记录总数:{}", aLong);
        log.info("数据源类型:{}", dataSource.getClass());
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

‍ 运行结果:

 数据源类型:class com.alibaba.druid.pool.DruidDataSource
1

‍

# 配置监控页

我们打开文档,可以看到有如何配置监控:

‍

简单来说,就是配置一个 Servlet 和访问路径,例如 web.xml:

  <servlet>
      <servlet-name>DruidStatView</servlet-name>
      <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
  </servlet>

  <servlet-mapping>
      <servlet-name>DruidStatView</servlet-name>
      <url-pattern>/druid/*</url-pattern>
  </servlet-mapping>
1
2
3
4
5
6
7
8
9

根据配置中的 url-pattern 来访问内置监控页面,如果是上面的配置,内置监控页面的首页是/druid/index.html

而在 SpringBoot 中,我们刚刚学习了如何注入 Servlet:

@Configuration
public class MyDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new DruidDataSource();
    }

    @Bean
    public ServletRegistrationBean statViewServlet() {
        StatViewServlet statViewServlet = new StatViewServlet();
        ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");
        return servletRegistrationBean;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

‍ 然后重启项目,访问 localhost: 9999/druid/index.html (opens new window),可以看到能正常访问:

‍

# 设置登录

一般来说,Druid 监控页是不能被随意访问的,不然很容易暴露一些敏感信息。我们可以通过配置,要登录后才能访问。

文档:

# 1.2 配置监控页面访问密码

需要配置 Servlet 的 loginUsername 和 loginPassword 这两个初始参数。

具体可以参考: 为 Druid 监控配置访问权限(配置访问监控信息的用户与密码) (opens new window)

示例如下:

<!-- 配置 Druid 监控信息显示页面 -->  
<servlet>  
    <servlet-name>DruidStatView</servlet-name>  
    <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>  
    <init-param>  
	<!-- 允许清空统计数据 -->  
	<param-name>resetEnable</param-name>  
	<param-value>true</param-value>  
    </init-param>  
    <init-param>  
	<!-- 用户名 -->  
	<param-name>loginUsername</param-name>  
	<param-value>druid</param-value>  
    </init-param>  
    <init-param>  
	<!-- 密码 -->  
	<param-name>loginPassword</param-name>  
	<param-value>druid</param-value>  
    </init-param>  
</servlet>  
<servlet-mapping>  
    <servlet-name>DruidStatView</servlet-name>  
    <url-pattern>/druid/*</url-pattern>  
</servlet-mapping>  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 2. 配置 allow 和 deny

StatViewSerlvet 展示出来的监控信息比较敏感,是系统运行的内部情况,如果你需要做访问控制,可以配置 allow 和 deny 这两个参数。比如:

  <servlet>
      <servlet-name>DruidStatView</servlet-name>
      <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
  	<init-param>
  		<param-name>allow</param-name>
  		<param-value>128.242.127.1/24,128.242.128.1</param-value>
  	</init-param>
  	<init-param>
  		<param-name>deny</param-name>
  		<param-value>128.242.127.4</param-value>
  	</init-param>
  </servlet>
1
2
3
4
5
6
7
8
9
10
11
12

‍

我们在 SpringBoot 中这样配置:

@Bean
public ServletRegistrationBean statViewServlet() {
    StatViewServlet statViewServlet = new StatViewServlet();
    ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");
    servletRegistrationBean.addInitParameter("loginUsername", "admin");
    servletRegistrationBean.addInitParameter("loginPassword", "123456");
    return servletRegistrationBean;
}
1
2
3
4
5
6
7
8

重启,此时就需要登录才能看到监控信息:

‍

# SQL 监控

我们可以试试 SQL 监控功能。先看看文档:

‍

文档大意:

Druid 内置提供一个 StatFilter,用于统计监控信息。

# 1. 别名配置

StatFilter 的别名是 stat,这个别名映射配置信息保存在 druid-xxx.jar!/META-INF/druid-filter.properties。

在 spring 中使用别名配置方式如下:

  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
  	... ...
  	<property name="filters" value="stat" />
  </bean>
1
2
3
4

‍ 也就是说,我们在数据源里要配置一个属性 filters,值是 stat。因此我们修改下注入 DataSource 时的属性:

@Configuration
public class MyDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setFilters("stat");
        return druidDataSource;
    }
    //.....
1
2
3
4
5
6
7
8
9
10
11

然后我们新增一个查询请求:

@Controller
public class IndexController {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @ResponseBody
    @GetMapping("/sql")
    public String queryFromDb() {
        Long aLong = jdbcTemplate.queryForObject("select count(*) from students", Long.class);
        return aLong.toString();
    }

    //..............
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

‍ 重启,访问/sql 路径,可以看到有结果了:

‍

关于什么是时间分布,可以参考文档中关于连接池的介绍:

‍

# 3.7 区间分布

SQL 监控项上,执行时间、读取行数、更新行数都有区间分布,将耗时分布成 8 个区间:

  • 0 - 1 耗时 0 到 1 毫秒的次数
  • 1 - 10 耗时 1 到 10 毫秒的次数
  • 10 - 100 耗时 10 到 100 毫秒的次数
  • 100 - 1,000 耗时 100 到 1000 毫秒的次数
  • 1,000 - 10,000 耗时 1 到 10 秒的次数
  • 10,000 - 100,000 耗时 10 到 100 秒的次数
  • 100,000 - 1,000,000 耗时 100 到 1000 秒的次数
  • 1,000,000 - 耗时 1000 秒以上的次数

记录耗时区间的发生次数,通过区分分布,可以很方便看出 SQL 运行的极好、普通和极差的分布。 耗时区分分布提供了“执行+RS 时分布”,是将执行时间+ResultSet 持有时间合并监控,这个能方便诊断返回行数过多的查询。

为了方便后续的配置,我们将 /sql 的路径放行下:

@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有请求,包括静态资源
                .excludePathPatterns("/", "/login", "/css/**", "/fonts/**", "/images/**", "/js/**", "/sql");
    }
}
1
2
3
4
5
6
7
8
9
10

# 监控 web 应用

例如配置 web 应用监控:

其本质也是配置一个 Servlet:

  <filter>
  	<filter-name>DruidWebStatFilter</filter-name>
  	<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
  	<init-param>
  		<param-name>exclusions</param-name>
  		<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>DruidWebStatFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
1
2
3
4
5
6
7
8
9
10
11
12

‍ 注意:经常需要排除一些不必要的 url,比如 .js,/css 等,这些配置在 init-param 中

在 SpringBoot 中,我们则通过注入的方式来配置:

@Bean
public FilterRegistrationBean webStatFilter() {
    WebStatFilter webStatFilter = new WebStatFilter();
    FilterRegistrationBean<WebStatFilter> filterFilterRegistrationBean = new FilterRegistrationBean<>(webStatFilter);
    filterFilterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
    filterFilterRegistrationBean.addInitParameter("exclusions", "*.js,*.css,/druid/*");
    return filterFilterRegistrationBean;
}
1
2
3
4
5
6
7
8

‍ 重启项目,然后多访问几次 /sql 路径,可以看到 web 应用和 URI 监控都与数据了:

‍

# SQL 注入(防火墙)

文档说明:

怎么配置防御 SQL 注入攻击:Druid 提供了 WallFilter,它是基于 SQL 语义分析来实现防御 SQL 注入攻击的。具体配置看这里: https://github.com/alibaba/druid/wiki/配置-wallfilter (opens new window)

‍

使用缺省配置的 WallFilter

  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
      ...
      <property name="filters" value="wall"/>
  </bean>
1
2
3
4

‍

WallFilter 可以结合其他 Filter 一起使用,例如:

  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
      ...
      <property name="filters" value="wall,stat"/>
  </bean>
1
2
3
4

‍

‍

因此,我们可以这样改配置:

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() throws SQLException {
    DruidDataSource druidDataSource = new DruidDataSource();
    druidDataSource.setFilters("stat,wall");
    return druidDataSource;
}
1
2
3
4
5
6
7

‍ 重启项目,然后多访问几次 /sql 路径,可以看到 SQL 防火墙有数据了:

# 简化配置

我们在注入 Servlet、Filter 的时候,调用了很多 set 方法,其实这些 set 方法,都是可以读取配置文件后自动 set 的:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/learnjdbc?serverTimezone=UTC
    username: learn
    password: learnpassword
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat,wall
1
2
3
4
5
6
7

‍ 然后方法中的 set 代码就可以注释掉了:

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() throws SQLException {
    DruidDataSource druidDataSource = new DruidDataSource();
//        druidDataSource.setFilters("stat,wall");
    return druidDataSource;
}
1
2
3
4
5
6
7

# 最后

本文我们讲了如何自己整合 Druid,下一篇讲如何用 starter 的方式来整合

已将本文源码上传到 Gitee (opens new window) 或 GitHub (opens new window) 的分支 demo10,读者可以通过切换分支来查看本文的示例代码

上次更新: 2025/6/3 09:31:54
数据库场景的自动配置分析和整合测试
通过 starter 整合 Druid

← 数据库场景的自动配置分析和整合测试 通过 starter 整合 Druid→

最近更新
01
学点统计学:轻松识破一本正经的胡说八道
06-05
02
2025 年 5 月记
05-31
03
《贫穷的本质》很棒,但可能不适合你
05-27
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式