MyBatis Plus 插件 动态数据源实现原理与源码讲解 (dynamic-datasource-spring-boot-starter-master)

这篇具有很好参考价值的文章主要介绍了MyBatis Plus 插件 动态数据源实现原理与源码讲解 (dynamic-datasource-spring-boot-starter-master)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. 介绍

2. 基本原理

3. 源码介绍

3.1 使用 AOP 拦截,方法执行前获取到当前方法要用的数据源

3.2 实现自定义 DataSource 接口,实现 DataSource 接口的 getConnect 方法做动态处理


1. 介绍

多数据源即一个项目中同时存在多个不同的数据库连接池。

比如 127.0.0.1:3306/test   127.0.0.1:3307/test 127.0.0.1:3308/test

总之项目存在需要操作多个库的需求。

具体在编码方面呢,具体就是一个service 中,方法1使用库1查询,方法2使用库2查询。

2. 基本原理

多数据源实现原理是什么呢?可分为两大关键部分

1. 使用 AOP 拦截,方法执行前获取到当前方法要用的数据源

可以使用自定义注解实现,注解参数带数据源名称,然后自己解析

2. 实现自定义 DataSource 接口,实现 DataSource 接口的 getConnect 方法做动态处理

动态处理,就是拿到 AOP 那一步获取到的数据源,直接返回该数据源

基本原理,可看这个简易图

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

3. 源码介绍

源码地址 https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter

(源码一定要自己完整看一遍,此篇博客只展示部分关键源码)

3.1 使用 AOP 拦截,方法执行前获取到当前方法要用的数据源

@DS 注解代表定义当前方法、当前类使用哪个数据源

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 value 指定当前类、方法使用的数据源名称

数据源名称也是在配置文件中定义的 

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

注解处理切面 DynamicDataSourceAnnotationAdvisor

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

切面 advice 由外部传过来,要处理的注解也从外面传过来。

也就是这里,这行代码的意思是

DynamicDataSourceAnnotationInterceptor 负责处理 DS 注解

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 接着看 DynamicDataSourceAnnotationInterceptor 如何处理

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

下面分别解释下

1. 将 @DS 注解的 value 值压入 ThreadLocal 当前线程的栈

看这段方法 DynamicDataSourceContextHolder.push(dsKey);

ThreadLocal 中存储的是 Deque 类,也就是一个双端队列(两头都可以插入的队列) ,使用的是 ArrayDeque 双端队列,内部是一个数组。

为什么使用队列,而不是简单一个字符串,注释已经写的很清楚了,看注释即可。

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 ArrayDeque 的 push 就是在队列首部添加一个元素。mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

2. 调用实际的方法

这里不是切面吗,实际方法也就是被拦截的方法。也就是直接调用业务逻辑。

3. 将第 1 步中的元素弹出来

业务逻辑执行完成后,就将刚才加入的元素弹出来。

其实这里很像 JVM 虚拟机栈,方法调用就是压入栈,方法结束调用就是出栈,栈顶就是当前执行的方法。

而此处这里的栈顶就代表 当前正在执行的方法所用的 数据源名称。而方法执行完了,这里也该出栈了。

这里核心逻辑已经完了,本质就是这么简单。

3.2 实现自定义 DataSource 接口,实现 DataSource 接口的 getConnect 方法做动态处理

DynamicRoutingDataSource 代表动态路由数据源

做的事情就是运行时动态路由出一个当前需要的数据源。

接着看源码,首先与 SpringBoot 整合时 自动配置出当前 Bean

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

DynamicRoutingDataSource 类图

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

3.2.1 DataSource

代表一个数据源,由javax 扩展定义

3.2.2 AbstractDataSource

抽象实现,将一些对数据源的配置操作都实现为不支持操作抛出异常 UnsupportedOperationException

(动态数据源相当于一个代理,不需要给动态数据源本身设置相关配置)

3.2.3 AbstractRoutingDataSource

抽象实现,路由动态配置源,实现了关键方法 getConnection ,完成了路由操作

看看源码  getConnection()

getConnection() 何时调用呢,也就是上一步的切面中的第 2 步中,invocation.proceed(),执行业务逻辑的过程中,遇到的 数据库层的操作时,就会到这里了。

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

这里直接看简单的非事务的获取数据源这里。

关键代码 determineDataSource().getConnection()

这个方法由子类实现,也就是下面的 DynamicRoutingDataSource

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

3.2.4 DynamicRoutingDataSource

动态路由数据源核心实现,完成 数据源的维护(添加删除数据源)数据源的选择

接着上面的源码流程,子类的 determineDataSource 方法最终调用了 getDataSource

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 getDataSource 源码如下

/**
 * 获取数据源
 *
 * @param ds 数据源名称
 * @return 数据源
 */
public DataSource getDataSource(String ds) {
    if (StringUtils.isEmpty(ds)) {
        // 没有指定数据源名称,直接使用默认的数据源
        return determinePrimaryDataSource();
    } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
        // 从分组数据源中找一个数据源
        return groupDataSources.get(ds).determineDataSource();
    } else if (dataSourceMap.containsKey(ds)) {
        // 直接根据名称找一个数据源
        return dataSourceMap.get(ds);
    }
    if (strict) {
        // 开启了严格模式时,如果没有找到数据源,就抛出异常
        throw new CannotFindDataSourceException("dynamic-datasource could not find a datasource named" + ds);
    }

    // 使用默认的数据源
    return determinePrimaryDataSource();
}

下面分别讲解关键之处

1. 没有指定数据源名称,直接使用默认的数据源

没有指定代表的是没有加 @DS 注解,或者加了注解,但是 value 值没有写

此时就是用默认的数据源,默认的数据源是什么呢?

也就是配置文件中的 primary 中指定的数据源名称,如果不配置的话默认值就是 master

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

2. 实现自定义 DataSource 接口,实现 DataSource 接口的 getConnect 方法做动态处理

从分组找一个数据源 groupDataSources.get(ds).determineDataSource();

分组是什么意思?

分组定义的规则是 group_xxx,也就是数据源名称以下划线分割,下划线前面的就是组名。

分组的作用是什么呢?本质用于实现一个名称对应多数据库源。

比如一主多从,可以将从数据源都分到 slave 组里面,用的时候就是 @DS("slave") // 组名

在实际决定数据源的时候,就会按照一定的策略从这个组里的数据源挑选一个了。

接着看源码,如何 从分组数据源中找一个数据源

groupDataSources.get(ds).determineDataSource();

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 最后到了策略的选择,DynamicDataSourceStrategy

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

DynamicDataSourceStrategy 有两个实现类

LoadBalanceDynamicDataSourceStrategy 负载均衡动态数据源策略

看源码,这个就是按顺序一个个选择下来,达到负载均衡方式

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

RandomDynamicDataSourceStrategy 随机动态数据源策略

这个完全就是纯随机选一个

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

3. 直接根据名称找一个数据源 

如果走到了这里,说明这个数据源名称没有配置分组,那就直接根据名称取这单个数据源了

直接纯 get 了

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

数据源何时初始化的

还是在 DynamicRoutingDataSource,这个类实现了 Spring InitializingBean 

接口回调方法 afterPropertiesSet,当当前 Bean 内部的属性都初始化完毕了后就回调这个方法

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 看看  afterPropertiesSet 回调方法内容

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 这里只看关键代码

1. dataSources.putAll(provider.loadDataSources());

@Autowired private List<DynamicDataSourceProvider> providers; providers 是什么呢 ? 

providers 代表 动态数据源配置的来源,默认实现就是从 yml 中来,也就是 SpringBoot 的 application.yml 配置

默认实现

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

传进去的参数配置类

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

DynamicDataSourceProvider 也就是解析了这些配置 来获取到所有配置

拿到配置后,就要解析这些配置了 ,这里委托了父类处理

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

这里完成创建数据源,然后将结果封装成了 Map<String, DataSource> dataSourceMap 返回

(泛型为 <数据源名称,数据源实例>)

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 看看如何创建数据源的 defaultDataSourceCreator.createDataSource(dataSourceProperty)

大致流程如下:

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

这里介绍一下 creators

dynamic-datasource-creator 模块下定义了单独数据源创建的代码

DataSourceCreator 代表一个数据源创建器,用于创建一个数据源。

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 每种数据源类型都有自己的创建器,比如这里常见的 Druid、Hikar

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

这里就举例其中一个 HikariDataSourceCreator,其他的都差不多

HikariDataSourceCreator

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

调用这些创造器的创建的时候默认直接就启动了,除非配置了懒加载。

到现在,数据源就已经创建完了。再次说一下这是在Spring 的 afterPropertiesSet 回调里完成创建的。(afterPropertiesSet  即当前 Bean 的所有属性 Spring 都填充完毕后回调)

2. addDataSource(dsItem.getKey(), dsItem.getValue());

上一步的 provider.loadDataSources() 讲解完毕了,这次看看下面的 addDataSource(dsItem.getKey(), dsItem.getValue());

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 addDataSource 方法

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

 首先是先给 dataSourceMap 放进去了。这里会返回旧的数据源(如果是第一次加入,则返回null),所以下面判断了如果返回有值旧关闭掉旧的数据源,关闭就是调用数据源的 close 方法。

然后是 addGroupDataSource

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot

这里数据源就完成了添加,这个整体步骤都是在启动的时候添加的, 后面的 getConnect 方法都只是获取了。 

最后再放这张图简单总结下。

mybatis-plus 动态数据源,其他框架源码,mybatis,java,spring boot文章来源地址https://www.toymoban.com/news/detail-733346.html

到了这里,关于MyBatis Plus 插件 动态数据源实现原理与源码讲解 (dynamic-datasource-spring-boot-starter-master)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • grpc + springboot + mybatis-plus 动态配置数据源

    前言 这是我在这个网站整理的笔记,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱 1.1 项目初始化 项目初始化的时候会调用com.baomidou.dynamic.datasource.DynamicRoutingDataSource对象的addDataSource方法添加数据源,数据源存进dataSourceMap中。 1.2 接口请求时候 进行数据操作时,

    2024年02月09日
    浏览(39)
  • springBoot-Mybatis-Plus 多数据源切换实现

    前言:本文主要通过AbstractRoutingDataSource,实现根据 http 访问携带的标识动态切换数据源; 1 AbstractRoutingDataSource 介绍: AbstractRoutingDataSource 是 Spring 框架中的一个抽象类,它可以用来实现动态数据源切换。在多数据源场景下,AbstractRoutingDataSource 可以根据不同的请求来动态地选

    2024年02月03日
    浏览(45)
  • SpringBoot整合Mybatis-Plus+Druid实现多数据源

    🌺本文主要讲解 springboot +mybatisplus + druid 实现多数据源配置功能 🌺 主页传送门:📀 传送 Spring Boot:    Spring Boot是一个基于Spring框架的开源Java开发框架,旨在简化Spring应用程序的开发、配置和部署。它提供了一种快速、敏捷的方式来构建独立的、生产级别的Spring应用程

    2024年02月09日
    浏览(102)
  • mybatis(plus)多数据源

         一个项目大部分都是单一数据库多一些,但是有时候会需要用多个库,所以这时候据需要使用多数据源。我这里使用springboot+mybatis(plus)+druid多数据源. 目前我知道有两种方式,一种方式是需要在service实现类上添加@DS,一种方式是通过配置的方式,配置不同的SqlSessionFac

    2024年02月06日
    浏览(43)
  • Spring Boot MyBatis Plus 配置数据源详解

    🎉欢迎来到架构设计专栏~Spring Boot MyBatis Plus 配置数据源详解 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:架构设计 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限,如果文

    2024年01月21日
    浏览(54)
  • Mybatis-plus多数据源单元测试@MybatisPlusTest

    mybatis-plus多数据源单元测试报错 错误原因分析 多数据源,但是不能取到数据信息 解决方案 在注解中添加 @ImportAutoConfiguration(value = {RmasDataSourceConfig.class}, exclude = DataSourceAutoConfiguration.class) 注意事项 1.@Test添加以后,没有启动键,后来发现引入的包不对,必须引入 org.junit.jup

    2024年02月11日
    浏览(41)
  • 手搭手入门Mybatis-Plus配置多数据源

    https://baomidou.com/ 为简化开发而生 MyBatis-Plus(opens new window)(简称 MP)是一个 MyBatis (opens new window) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 无侵入 :只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 损耗小 :启动即会自

    2024年02月07日
    浏览(40)
  • SpringBoot整合Mybatis-Plus、Druid配置多数据源

    目录 1.初始化项目 1.1.初始化工程 1.2.添加依赖 1.3.配置yml文件 1.4.Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹 1.5.配置使用数据源 1.5.1.注解方式 1.5.2.基于AOP手动实现多数据源原生的方式 2.结果展示 Mybatis-Plus:简介 | MyBatis-Plus (baomidou.com) 在正式开始之前,先初始

    2024年02月11日
    浏览(45)
  • spring多数据源动态切换的实现原理及读写分离的应用

    AbstractRoutingDataSource 是Spring框架中的一个抽象类,可以实现多数据源的动态切换和路由,以满足复杂的业务需求和提高系统的性能、可扩展性、灵活性。 多租户支持:对于多租户的应用,根据当前租户来选择其对应的数据源,实现租户级别的隔离和数据存储。 分库分表:为了

    2024年02月14日
    浏览(39)
  • 【SpringBoot 3.x】整合Mybatis-Plus多数据源、Druid

    开发依赖 版本 Spring Boot 3.0.6 Mybatis-Plus 3.5.3.1 dynamic-datasource-spring-boot-starter 3.6.1 JDK 20 SpringBoot启动类修改 由于排除了DruidDataSourceAutoConfigure类的自动装载,就需要手工指定装配以下几个类 查看DruidDataSourceAutoConfigure这个类的源码可以看出,需要把@Import带进来的几个类进行自动装

    2024年02月04日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包