找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1175

积分

0

好友

153

主题
发表于 17 小时前 | 查看: 0| 回复: 0

在当今的服务器开发中,采用 SpringBoot3.x + MyBatisPlus + Druid 来构建多数据源配置几乎已成为一种标准实践。Druid本身也支持多数据源,但 MyBatis Plus 团队提供了一个独立的多数据源管理组件,它对部分功能进行了重写,因此配置方式与原生Druid有所不同。如果你选择了MyBatis Plus的动态数据源方案,可能会在配置文件中发现一个“小坑”:配置Druid监控相关的参数时,IDE往往不会给出任何提示,这容易让人误以为该方案不支持这些功能。最近在新项目中实际配置了一遍,在此将关键步骤记录下来,希望能帮到有同样需求的开发者。

添加Maven依赖

首先,需要在项目的 pom.xml 文件中引入必要的依赖。

<!-- 阿里数据库连接池 -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-3-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-3-starter</artifactId>
            <version>1.2.22</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.5</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-annotation</artifactId>
            <version>3.5.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!-- mybatis plus的动态数据源 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
            <version>4.2.0</version>
        </dependency>

理解自动配置与排除冲突

MyBatis Plus 多数据源功能的自动装配核心类是 DynamicDataSourceAutoConfiguration

MyBatis Plus动态数据源自动配置类源码截图

这个配置类中通过 @Import 注解引入了阿里的 Druid 配置类,实际上是复用了其功能:

Druid动态数据源配置类导入语句截图

由于此时项目中同时存在原生 Druid 的自动配置类和 MyBatis Plus 引入的配置类,为了避免冲突,我们需要在应用启动时排除掉原生的 DruidDataSourceAutoConfigure

Spring Boot启动类排除Druid自动配置截图

关键配置文件详解

接下来是配置的重头戏。在 application.yml 中,我们需要正确配置数据源和 Druid 监控。注意,在 spring.datasource.druid 下的监控配置,IDE可能不会提示,但它是有效的。

# 数据源配置
spring:
  data:
    redis:
      host: 192.168.3.102
      port: 6379
      password: 123456
  datasource:
    druid:
      filter:
        stat:
          enabled: true
      # 开启druid的sql统计及监控,注意这里配置的时候idea不会提示,估计是因为是去掉阿里数据源的问题
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        # 控制台管理用户名和密码,记得生产环境的时候,此接口最好是在安全的环境中访问
        login-username: admin
        login-password: 123456
        reset-enable: false
        allow: 192.168.3.25,127.0.0.1  # 允许访问的ip白名单
      web-stat-filter:
        enabled: true
        url-pattern: /*

    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    dynamic:
      primary: master
      lazy: false
      datasource:
        # 主库数据源
        master:
          url: jdbc:mysql://192.168.3.102:3306/ciyan_mmo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
          username: root
          password: 123456
        # 从库数据源
        #        slave:
        #          url:
        #          username:
        #          password:
      druid:
        # 初始连接数
        initialSize: 5
        # 最小连接池数量
        minIdle: 10
        # 最大连接池数量
        maxActive: 20
        # 配置获取连接等待超时的时间
        maxWait: 60000
        # 配置连接超时时间
        connectTimeout: 30000
        # 配置网络超时时间
        socketTimeout: 60000
        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        timeBetweenEvictionRunsMillis: 60000
        # 配置一个连接在池中最小生存的时间,单位是毫秒
        minEvictableIdleTimeMillis: 300000
        # 配置一个连接在池中最大生存的时间,单位是毫秒
        maxEvictableIdleTimeMillis: 900000
        # 配置检测连接是否有效
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        filters: stat,wall

访问监控页面与常见问题

服务启动后,就可以通过浏览器访问 Druid 的监控页面了,地址是:http://127.0.0.1:9901/druid/login.html (端口请替换为你项目的实际 Web 服务端口)。

Druid监控登录界面

如果你访问 login.html 时页面一片空白,服务器没有返回响应内容,那很可能是你自定义的过滤器“拦截”了这次请求。例如,如果你使用了 ContentCachingResponseWrapper 来包装响应,但在过滤器链的最后没有调用 copyBodyToResponse() 方法,就会导致这种情况。正确的写法示例如下:

package cn.jw.starter.web.core.filters;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import cn.hutool.extra.spring.SpringUtil;
import cn.jw.starter.web.core.properties.JwWebProperties;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * 缓存请求消息的filter,
 *
 * @author 王广帅
 * @since 2024/4/3 20:31
 */
public class CacheRequestBodyFilter extends OncePerRequestFilter {

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String uri = request.getRequestURI();
        // 静态资源都不要走这个过滤
        if (uri.endsWith(".html") || uri.endsWith(".js") || uri.endsWith(".css") || uri.endsWith(".ico")) {
            return true;
        }
        JwWebProperties jwWebProperties = SpringUtil.getBean(JwWebProperties.class);
        if (jwWebProperties.getIgnoreCacheBodyUriList().contains(uri)) {
            return true;
        }
        return super.shouldNotFilter(request);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        logger.debug("先走一步");
        if (request.getContentLength() > 0 && !(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
            request.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
            response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
        }
        filterChain.doFilter(request, response);
        updateResponse(response);
    }

    /**
     * 更新响应(不操作这一步,会导致接口响应空白)
     *
     * @param response
     *            响应对象
     * @throws IOException
     *             /
     */
    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper =
            WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (responseWrapper != null) {
            Objects.requireNonNull(responseWrapper).copyBodyToResponse();
        }
    }
}

这里有个容易混淆的点:我曾误将 updateResponse 的逻辑写在 HandlerInterceptor 的实现类中。但需要注意的是,HandlerInterceptor 主要拦截 Controller 层的请求,而 Druid 监控页面的请求是直接访问 Servlet 的,不会经过 HandlerInterceptor,因此过滤器才是正确的位置。


看文章累了,来修个仙吧!黄色卡通比心手势表情包

希望这篇关于 SpringBoot3 整合 MyBatis Plus 多数据源与开启 Druid 监控的实战记录能对你有所帮助。如果你在 Java 后端开发中遇到其他架构或数据库相关的问题,欢迎到 云栈社区 与其他开发者一起交流探讨。




上一篇:LangGraph多智能体工作流:架构设计与核心机制解析
下一篇:ROG B850-I 迷你ITX主板深度评测:AMD B850芯片组与WiFi 7加持的装机实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-9 21:59 , Processed in 0.322370 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表