MybatisPlus 多数据源 @DS 选择深入源码理解原理

文章目录

  • MybatisPlus 多数据源 @DS 选择深入源码理解原理

MybatisPlus 多数据源 @DS 选择深入源码理解原理

数据源的选择,拦截器为DynamicDataSourceAnnotationInterceptor

image-20240710134040796

这里利用了一个MethodInterceptor接口,我们看看,我们可以看到这个包是org.aopalliance.intercept通过搜索得知

image-20240710134135389

aopalliance是对AOP和Java有浓厚兴趣的软件开发人员联合成立的开源项目,Spring是按照AOP联盟的规范做的实现,可见Spring是一个集众多基础框架于一身的伟大软件。aopalliance包里面只有接口,没有任何实现,这就是一个规范定义。

下面借用了一张图,spring aop实现了aopalliance的接口

img

现在我们知道了这个MethodInterceptor会拦截方法,类似于apesctJ里的around环绕通知。我们看看mybatisplus的拦截器是怎么处理的

image-20240710135704171

核心代码就这三行,在方法执行前先确定数据源推入到DynamicDataSourceContextHolder,然后再执行方法,再poll出用过的这个数据源,这个玩意是用来持有当前线程要用哪个数据源的。废话不多说直接看源码

image-20240710135901474

这个玩意很简单,就是用来持有当前线程调每个方法时要用哪个数据源,在方法执行之前把这个方法要用的数据源字符串压入栈,执行完弹出。在数据保存的时候他用的Deque,我们看到初始化的时候用的new ArrayDeque<>(),顺便看看这个ArrayDeque底层,其实就是一个对象数组、队列头、尾,默认数组长度16

image-20240710140055287

那么再看下它进入方法之前是怎么获取数据源字符串的,determineDatasource方法

image-20240710140355285

这个方法也很简单,获取当前被执行方法,如果这个方法上有DS注解,那就用这个注解,没有的话再去看这个方法所在类上有没有DS注解,有的话就用这个注解。有了注解之后还做了个判定是不是动态数据源表达式(DYNAMIC_PREFIX开头的,就是#开头的),如果是用了动态表达式的再执行动态表达式解析。我们点进去看这个抽象类DsProcessor,抽象方法doDetermineDatasource是有三个实现的:请求头处理器,Session处理器,表达式处理器

请求头和Session处理器很简单,就是从请求头里去拿,Session里拿直接的字符串,而表达式处理器则麻烦一些,在这里不深入了,想看的去看DsSpelExpressionProcessor类,就截个图略微看一下把

image-20240710140541724

image-20240710141058483

image-20240710141109817

image-20240710141036124

前面我们看到拦截器是实现MethodInterceptor实现的,那拦截的是哪些方法呢,我们看源码里的自动配置类,我们去看每个框架的时候都可以从关键功能或者自动配置文件去作为入口,在里面我们可以看到有个DynamicDataSourceAnnotationAdvisor,动态数据源注解通知,我们看源码里怎么写的

/*** 动态数据源核心自动配置类** @author TaoYu Kanyuxia* @see DynamicDataSourceProvider* @see DynamicDataSourceStrategy* @see DynamicRoutingDataSource* @since 1.0.0*/
@Slf4j
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@Import(value = {DruidDynamicDataSourceConfiguration.class, DynamicDataSourceCreatorAutoConfiguration.class})
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class DynamicDataSourceAutoConfiguration {private final DynamicDataSourceProperties properties;@Bean@ConditionalOnMissingBeanpublic DynamicDataSourceProvider dynamicDataSourceProvider() {Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();return new YmlDynamicDataSourceProvider(datasourceMap);}@Bean@ConditionalOnMissingBeanpublic DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();dataSource.setPrimary(properties.getPrimary());dataSource.setStrict(properties.getStrict());dataSource.setStrategy(properties.getStrategy());dataSource.setProvider(dynamicDataSourceProvider);dataSource.setP6spy(properties.getP6spy());dataSource.setSeata(properties.getSeata());return dataSource;}@Bean@ConditionalOnMissingBeanpublic DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor();interceptor.setDsProcessor(dsProcessor);DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);advisor.setOrder(properties.getOrder());return advisor;}@Bean@ConditionalOnMissingBeanpublic DsProcessor dsProcessor() {DsHeaderProcessor headerProcessor = new DsHeaderProcessor();DsSessionProcessor sessionProcessor = new DsSessionProcessor();DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();headerProcessor.setNextProcessor(sessionProcessor);sessionProcessor.setNextProcessor(spelExpressionProcessor);return headerProcessor;}@Bean@ConditionalOnBean(DynamicDataSourceConfigure.class)public DynamicDataSourceAdvisor dynamicAdvisor(DynamicDataSourceConfigure dynamicDataSourceConfigure, DsProcessor dsProcessor) {DynamicDataSourceAdvisor advisor = new DynamicDataSourceAdvisor(dynamicDataSourceConfigure.getMatchers());advisor.setDsProcessor(dsProcessor);advisor.setOrder(Ordered.HIGHEST_PRECEDENCE);return advisor;}
}

我们可以看到源码里用spring aop的AnnotationMatchingPointcut 注解匹配切入点来对 方法/类上加了@DS注解的方法做了拦截。

image-20240710142338335

image-20240710142408701

在自动配置类最下面还有个AOP配置是DynamicDataSourceAdvisor,我们看源码理解,构建切入点Pointcut的时候用的DynamicJdkRegexpMethodPointcut,这个是继承的spring aop的JdkRegexpMethodPointcut,并多了matchesCache和ds两个字段。其实就是利用正则表达式来匹配方法,然后决定数据源。配置在配置文件中。而我们平时一般用注解的方式比较多。

/*** Copyright © 2018 organization baomidou* <pre>* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.* <pre/>*/
package com.baomidou.dynamic.datasource.aop;import com.baomidou.dynamic.datasource.matcher.ExpressionMatcher;
import com.baomidou.dynamic.datasource.matcher.Matcher;
import com.baomidou.dynamic.datasource.matcher.RegexMatcher;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import lombok.Setter;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author TaoYu* @since 1.2.0*/
public class DynamicDataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {/*** The identification of SPEL*/private static final String DYNAMIC_PREFIX = "#";@Setterprivate DsProcessor dsProcessor;private Advice advice;private Pointcut pointcut;private Map<String, String> matchesCache = new HashMap<>();public DynamicDataSourceAdvisor(List<Matcher> matchers) {this.pointcut = buildPointcut(matchers);this.advice = buildAdvice();}private Advice buildAdvice() {return new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {try {Method method = invocation.getMethod();String methodPath = invocation.getThis().getClass().getName() + "." + method.getName();String key = matchesCache.get(methodPath);if (key != null && !key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) {key = dsProcessor.determineDatasource(invocation, key);}DynamicDataSourceContextHolder.push(key);return invocation.proceed();} finally {DynamicDataSourceContextHolder.poll();}}};}@Overridepublic Pointcut getPointcut() {return this.pointcut;}@Overridepublic Advice getAdvice() {return this.advice;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {if (this.advice instanceof BeanFactoryAware) {((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);}}private Pointcut buildPointcut(List<Matcher> matchers) {ComposablePointcut composablePointcut = null;for (Matcher matcher : matchers) {if (matcher instanceof RegexMatcher) {RegexMatcher regexMatcher = (RegexMatcher) matcher;Pointcut pointcut = new DynamicJdkRegexpMethodPointcut(regexMatcher.getPattern(), regexMatcher.getDs(), matchesCache);if (composablePointcut == null) {composablePointcut = new ComposablePointcut(pointcut);} else {composablePointcut.union(pointcut);}} else {ExpressionMatcher expressionMatcher = (ExpressionMatcher) matcher;Pointcut pointcut = new DynamicAspectJExpressionPointcut(expressionMatcher.getExpression(), expressionMatcher.getDs(),matchesCache);if (composablePointcut == null) {composablePointcut = new ComposablePointcut(pointcut);} else {composablePointcut.union(pointcut);}}}return composablePointcut;}
}

image-20240710142802210

image-20240710142813234

数据源的确定,数据源的选择都已经知道了,我们看下数据源的加载,在自动配置类里有个DynamicDataSourceProvider我们点进去看其实就是个保存数据源名称和数据源包装对象的map罢了。而这个数据源的配置从哪里来的呢,是从DynamicDataSourceProperties来的,看下面截图,其实就是你在配置文件里配的spring.datasource.dynamic这个前缀下的配置。

image-20240710143343989

image-20240710143020793

image-20240710143325140

我们去Nacos配置里配的就是这样的配置,至此MybatisPlus多数据源的原理你就完整掌握啦

image-20240710143644313

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/869641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

防御笔记第四天(持续更新)

1.状态检测技术 检测数据包是否符合协议的逻辑顺序&#xff1b;检查是否是逻辑上的首包&#xff0c;只有首包才会创建会话表。 状态检测机制可以选择关闭或则开启 [USG6000V1]firewall session link-state tcp ? check Indicate link state check [USG6000V1]firewall ses…

CLion学习笔记-cmake编译和多main函数编译

这里就不讲怎么配置clion了 项目名字 pcl_kdtree_search 1.新建一个工程名字自己取&#xff0c;我这里用自己学习pcl的&#xff0c;加一个main函数&#xff0c;这个时候Cmake里边就是这样的。 #声明要求的cmake最低版本 cmake_minimum_required(VERSION 3.19) #声明一个工程…

消息称台积电下周开始试产 2nm 芯片,有望率先用于苹果 iPhone 17

消息称台积电下周开始试产 2nm 芯片&#xff0c;有望率先用于苹果 iPhone 17 &#x1f4a1;&#x1f4f1; 大家好&#xff0c;我是猫头虎&#xff0c;科技自媒体博主 &#x1f431;&#x1f42f;&#xff0c;带你洞察科技世界的每一个细节&#xff01;&#x1f525; 关于猫头…

sklearn(Python机器学习库)介绍

0 引言 Sklearn (全称 Scikit-Learn)是基于Python 编程语言的免费软件机器学习库。 Scikit-learn主要是用Python编写的,它建立在 NumPy, SciPy, Pandas 和 Matplotlib 之上,里面API 的设计非常好,所有对象的接口简单,很适合新手上路。 Scikit-learn与许多其他Python库很好地…

MAT(Eclipse Memory Analyzer) Windows安装

MAT&#xff08;Eclipse Memory Analyzer&#xff09; Windows安装 MAT&#xff08;Eclipse Memory Analyzer&#xff09;是一个Java的内存分析工具 MAT下载地址 安装完成之后的目录机构 如若出现java版本过低的解决办法 在配置文件MemoryAnalyzer.ini中添加指定Java的版本…

PD协议诱骗芯片,XSP08Q,XSP16应用笔记

XSP08Q是3C数码或小家电产品的Type-C接口控制芯片&#xff0c;它负责和PD充电器通讯&#xff0c;获取充电器的快充电压档位&#xff0c;如5V4A&#xff0c;9V3A&#xff0c;12V2A&#xff0c;15V3A&#xff0c;20V5A等等。 XSP08Q支持PD协议&#xff0c;BC1.2协议&#xff0c;Q…

从产业链视角审视工作

从产业链视角审视工作&#xff1a;定位、价值与成长 作为一名技术博客博主&#xff0c;我经常收到各种关于职业发展、技术成长和学习路径的问题。最近&#xff0c;我看了一份学习报告&#xff0c;其中提到了一种非常有趣且实用的视角——从产业链的角度去审视自己的工作。这种视…

Web 自动化测试主流框架都有哪些?

Web移动端自动化测试成为了现代软件开发流程中的重要环节&#xff0c;因此&#xff0c;很多主流框架被开发出来来帮助开发人员提高测试效率。本篇文章将从零到一详细介绍Web移动端自动化测试的主流框架。 一、Web移动端自动化测试框架简介 Web移动端自动化测试框架是一种开发工…

百元平价蓝牙耳机哪款好?平价高性价比蓝牙耳机推荐

随着蓝牙耳机的普及&#xff0c;市面上各种品牌的蓝牙耳机也层出不穷。对于那些预算在百元平价的朋友来说&#xff0c;百元平价蓝牙耳机哪款好&#xff1f;这个问题就显得格外重要了。毕竟&#xff0c;蓝牙耳机作为日常生活中不可或缺的小伙伴&#xff0c;不仅需要音质出众、续…

AD3518 SOP-8封装 单节锂电池保护芯片 可替代XB8608/XB8608A

AD3518 是一款内置 MOSFET 的单节锂电池保护芯片。该芯片具有非常低的功耗和非常低阻抗的内置 MOSFET。该芯片有充电过压&#xff0c;充电过流&#xff0c;放电过压&#xff0c;放电过流&#xff0c;过热&#xff0c;短路&#xff0c;电芯反接等各项保护等功能&#xff0c;确保…

7.深度学习概述

深度学习概述 1. 线性回归1.1 线性回归一般表达式1.2 线性回归内积表达方式&#xff1a;1.3 多个样本时&#xff0c;线性回归的进一步表达&#xff1a;1.4 线性回归方程的解析1.5 线性回归就是求loss函数的最小值 2. 如何求函数最小值2.1 一个例子2.2 求导法——求最小值2.3 求…

使用“nvm use 版本号“命令无效

使用"nvm use 版本号"命令无效 为什么无效?解决 为什么无效? 解决 将这个nodejs文件夹删除,然后在运行nvm use 版本号,则 node生效.

FastAPI 学习之路(三十四)数据库多表操作

之前我们分享的是基于单个表的数据库表的操作&#xff0c;我们在设计数据库的时候也设计了跨表&#xff0c;我们可以看下数据库的设计 class User(Base):__tablename__ "users"id Column(Integer, primary_keyTrue, indexTrue)email Column(String(10), uniqueTr…

不想成为失业大军,就要学习六西格玛?

最近&#xff0c;优思学院收到一封邮件&#xff0c;这封邮件的发送者是一位完成了我们六西格玛绿带课程的学生。 他的公司裡有20%的工程师被裁员&#xff0c;但值得注意的是&#xff0c;留下来的工程师中有70%人竟然都持有六西格玛绿带或黑带证书。 他的公司不仅希望利用这些…

el-table封装popver組件,点击列筛选行数据功能,支持筛选,搜索,排序功能

子组件&#xff1a; <template><div class"tableTool" ref"tableTool" click.stop><el-button click"shengFnc">升序</el-button><el-button click"jiangFnc">降序</el-button><el-input v-m…

安卓 APK 安装过程详解

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Android ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 1. 开机后连上网线 2. 查看网线的IP地址 3. 检查ADB连接 4. 修改文件权限 步骤 结语 我的其他博客 前言 在安卓设备上安装…

python3 ftplib乱码怎么解决

其实很简单。ftplib.FTP里面有个参数叫encoding。 如上图最后一行。所以在使用FTP时&#xff0c;主动指定编码格式即可。 ftp ftplib.FTP() ftp.encoding "utf-8" 再使用就可以了。

!vue3中defineEmits接收父组件向子组件传递方法,以及方法所需传的参数及类型定义,避免踩坑!

使用说明 1、在子组件中调用defineEmits并定义要发射给父组件的方法 const emits defineEmits([‘foldchange’]) 2、使用defineEmits会返回一个方法&#xff0c;使用一个变量emits(变量名随意)去接收 3、在子组件要触发的方法中&#xff0c;调用emits并传入发射给父组件的方法…

Kimi携手思维链,点亮论文写作之路!

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在学术的海洋中&#xff0c;思想的火花常常在静谧的图书馆角落或深夜的电脑屏幕前迸发。今天分享的内容是一种高阶的论文写作方法&#xff1a;Kimi思维链。 Kimi&#xff0c;一个由月之…

【数据结构和算法的概念等】

目录 一、数据结构1、数据结构的基本概念2、数据结构的三要素2.1 数据的逻辑结构2.2 数据的存储&#xff08;物理&#xff09;结构2.3 数据的运算 二、算法1、算法概念2、算法的特性及特点3、算法分析 一、数据结构 1、数据结构的基本概念 数据&#xff1a; 是所有能输入到计…