自定义注解实现动态数据源

在Java开发中,使用多数据源能够提高系统的灵活性和性能。本文将通过介绍自定义注解的方式,实现动态数据源的切换。通过这种创新性的方法,开发者可以根据业务需求轻松切换数据库连接,实现数据源的动态管理,提升系统的可扩展性和响应性。通过深入了解自定义注解的原理,读者将能够更好地利用这一特性,优化数据库访问策略,提高应用程序的整体性能。

怎么通过自定义注解和面向切面的方式结合实现动态切换数据源。
代码实践,controller层根据id获取用户信息

@RestController
public class UserController {@Resourceprivate UserService userService;@GetMapping("/v1/user/{id}")@UsingDataSource("ds1")public User getById1(@PathVariable String id) {return userService.getByUserId1(id);}@GetMapping("/v2/user/{id}")public User getById2(@PathVariable String id) {return userService.getByUserId2(id);}
}

service层上注解一个是数据源1,一个是数据源2

public interface UserService {@UsingDataSource("ds1")User getByUserId1(String userId);@UsingDataSource("ds2")User getByUserId2(String userId);}

在spring框架中要实现动态数据源一个核心的类就是AbstractRoutingDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getKey();}
}

同时把他注册到IOC容器中

//省略代码。。
@Beanpublic DynamicDataSource dynamicDataSource() {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("ds1", dataSource1());targetDataSources.put("ds2", dataSource2());DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(dataSource1());return dynamicDataSource;}@ConfigurationProperties("datasource1")//数据源1@Beanpublic DataSource dataSource1() {return DataSourceBuilder.create().build();}//数据源2@Bean@ConfigurationProperties("datasource2")public DataSource dataSource2() {return DataSourceBuilder.create().build();}//省略代码。。

使用上下文的容器存放这个key,他是线程安全的

public class DataSourceContextHolder {public static ThreadLocal<String> key = new ThreadLocal<>();public static void setKey(String key) {DataSourceContextHolder.key.set(key);}public static String getKey() {return key.get();}//每次使用完都要清空掉,线程绑定的keypublic static void clearKey() {key.remove();}
}

现在我们了解了想要动态切换数据源,在调用查找数据库之前设置这个key值,这样就可以使spring使用动态数据源的实现类根据key找到对应的数据库信息。

想要实现动态数据源的话,需要自己实现sqlSessionFactoryBean

    @Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DynamicDataSource dynamicDataSource) throws IOException {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();/** 设置mybatis configuration 扫描路径 */PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));//加载配置文件的地址;////自己实现的动态数据源bean.setDataSource(dynamicDataSource);return bean;}//事务管理器也设置自定义的数据源@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dynamicDataSource());}

切面类的实现

@Aspect
@Component
public class DataSourceAspect {//以自定义注解的方式切入,在加了这个注解的方法上切入@Pointcut("@annotation(com.example.demo.datasource.UsingDataSource)")public void checkPointCut() {}//在执行方法之前切入@Before("checkPointCut()")public void checkBefore(JoinPoint joinPoint) {try {//获取切入方法上的注解Class<?> clazz = joinPoint.getTarget().getClass();String methodName = joinPoint.getSignature().getName();Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();Method method = clazz.getMethod(methodName, parameterTypes);UsingDataSource usingDataSource = method.getAnnotation(UsingDataSource.class);//给上下文容器中设置keyString dataSourceKey = usingDataSource.value();DataSourceContextHolder.setKey(dataSourceKey);} catch (NoSuchMethodException e) {e.printStackTrace();}}//方法调用之后清理上下文中的key@After("checkPointCut()")public void checkAfter(){DataSourceContextHolder.clearKey();}
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface UsingDataSource {String value() default "";
}

整个过程结束

一些情况会导致动态代理失效,也就会导致aop失效,比如在service层中调用getByUserId,使用的数据源不是ds2

    //省略部分代码@Overridepublic User getByUserId(String userId) {return getByUserId2(userId);}@Override@UsingDataSource("ds2")public User getByUserId2(String userId) {return userDao.getById(Integer.parseInt(userId));}

如果想要代理不失效,可以获取当前代理对象,然后通过该代理对象调用了 getByUserId2 方法,同时需要暴露代理类,在启动类上配置@EnableAspectJAutoProxy(exposeProxy = true)

    @Overridepublic User getByUserId(String userId) {UserService o = (UserService) AopContext.currentProxy();return o.getByUserId2(userId);}@Override@UsingDataSource("ds2")public User getByUserId2(String userId) {return userDao.getById(Integer.parseInt(userId));}

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

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

相关文章

C++类和对象(中)

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

如何在Win系统安装Jupyter Notbook并实现无公网ip远程访问本地笔记

文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 在数据分析工作中&#xff0c;使用最多的无疑就是各种函数、图表、…

Mybatis-Plus基础

typora-copy-images-to: img Mybatis Plus 今日目标&#xff1a; 了解mybatisplus的特点能够掌握mybatisplus快速入门能够掌握mybatisplus常用注解能够掌握mybatisplus常用的增删改查能够掌握mybatisplus自动代码生成 1 MybatisPlus简介 1.1 MybatisPlus概述 ​ MyBatis-…

【前端web入门第二天】03 表单-下拉菜单 文本域 label标签 按钮 【附注册信息综合案例】

文章目录: 1. 下拉菜单 2. 文本域3.label标签 4.按钮- button 4.1 reset重置按钮结合form表单区域使用 5.无语义的布局标签 6.字符实体 注册信息综合案例 表单第二节 1. 下拉菜单 标签: select嵌套option,select是下拉菜单整体&#xff0c;option是下拉菜单的每一项。 代码…

MySQL运维实战(5.1) 字符和编码的基本概念

作者&#xff1a;俊达 字符和编码 字符 字符是符号&#xff0c;是人们用于交流的各类符号&#xff0c;如26个英文字母、汉字、标点符号、数学运算符、其他语言的字母和符号。 编码 编码是计算机中以二进制方式存储字符的方式。每个字符都有一个对应的编码值&#xff0c;计算机…

HarmonyOS --@state状态装饰器

在声明式UI中&#xff0c;是以状态驱动视图更新。 状态&#xff08;state&#xff09;&#xff1a;指驱动视图更新的数据&#xff08;被装饰器标记的变量&#xff09;。 试图&#xff08;view&#xff09;&#xff1a;基于UI描述渲染得到用户界面 State装饰器标记的变量必须初…

FPGA硬件架构

1.Xilinx FPGA是异构计算平台&#xff08;所谓异构&#xff0c;就是有很多不同的部分组成&#xff09;&#xff1a;CLB,BRAM,DSP 2. 软核&#xff1a; 把经过功能验证的、可综合的、实现后电路结构总门数在五千门以上的Verilog HDL模型称为软核(soft core)。 硬核: 把在某一…

数字化人才培养-流量的认知

1、流量的分类 公域/商域/私域 公域&#xff1a;公域流量指商家直接入驻平台实现流量转换&#xff0c;比如大家熟悉的拼多多、京东、淘宝、饿了么等&#xff0c;以及内容付费行业的喜马拉雅、知乎、得到等公域流量平台。 公域流量典型的代表有&#xff1a;抖音视频的曝光量、…

JavaScript DOM属性和方法之attribute属性对象

在HTML的DOM中&#xff0c;attribute对象表示HTML属性。HTML属性始终属于HTML元素&#xff0c;它在DOM节点中被称为属性节点。在DOM中&#xff0c;NamedNodeMap对象表示元素属性节点的无序集合&#xff0c;我们可以通过指定的索引访问指定的属性。通过element对象的attribute属…

小红树上染色

记忆化深搜 #include <iostream> #include <string> #include <stack> #include <vector> #include <queue> #include <deque> #include <set> #include <map> #include <unordered_map> #include <unordered_set&g…

JAVAEE初阶 网络编程(六)

TCP协议 一. 四次挥手二. 连接管理过程中TCP状态的变化2.1 listen状态2.2 established状态2.3 CLOSE_WAIT状态2.4 TIME_WAIT状态 三. 滑动窗口3.1 ack丢了3.2 数据丢了 一. 四次挥手 我们都知道&#xff0c;在三次握手中是可以把中间步骤合并成一个步骤执行&#xff0c;那么在四…

C语言数据结构(4)——线性表其三(双向链表)

欢迎来到博主的专栏——C语言数据结构 博主ID&#xff1a;代码小豪 文章目录 链表的种类头结点循环链表双向链表带头双向循环链表带头双向循环链表的定义与初始化 空链表尾插法打印双向链表头插法查找指定数据项的节点在指定位置之后插入节点指定位置的删除双向链表的销毁 顺序…

C语言第十二弹--扫雷

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 扫雷 1、扫雷游戏分析和设计 1.1、扫雷游戏的功能说明 1.2 游戏的分析和设计 1.2.1、数据结构的分析 1.2.2、文件结构设计 2、扫雷游戏的结构分析 2.1、用…

vmware虚拟机centos8共享文件夹挂载

1.设置虚拟机共享文件夹 2. 上述设置完毕之后&#xff0c;重启进入虚拟机&#xff0c;查看出现的共享文件夹名称 vmware-hgfsclient 3.查看是否有挂载目录&#xff0c;挂在目录默认为 /mnt/hgfs。没有时可以使用以下命令创建 mkdir /mnt/hgfs 4. 手动挂载目录--只能实现一次 注…

LarkXR引入2D共享模式,CloudXR新体验

Paraverse平行云自主研发的LarkXR&#xff0c;作为CloudXR解决方案的领军者&#xff0c;已在业界实现了显著的创新突破。LarkXR通过分钟级部署大规模云端资源、高度适配所有主流XR引擎&#xff0c;并灵活支持不同的交互和沉浸方式&#xff0c;成功地解决了Cloud XR商业化过程中…

Arduino Uno R3通过ESP-01S连接网络

一、材料准备 Arduino Uno R3开发板 1 USB串口通信数据线&#xff08;Uno开发板使用&#xff09; 1 ESP8266-01S Wi-Fi模块 1 ESP8266固件烧录下载器&#xff08;烧录固件使用&#xff09; 1 WiFi无线收发转接板&#xff08;适用于ESP-01S、ESP-01&#xff09; 杜邦线…

java设计模式:工厂模式

1&#xff1a;在平常的开发工作中&#xff0c;我们可能会用到不同的设计模式&#xff0c;合理的使用设计模式&#xff0c;可以提高开发效率&#xff0c;提高代码质量&#xff0c;提高系统的可拓展性&#xff0c;今天来简单聊聊工厂模式。 2&#xff1a;工厂模式是一种创建对象的…

如何查看某网站的谷歌流量的组成情况

在独立站跨境贸易当中&#xff0c;很多时候我们都会重复一个动作&#xff0c;那就是查看对手网站或者某一网站的流量&#xff0c;以此来分析和总结如何优化自己的站点&#xff0c;借鉴对手优秀的地方来补足自己的缺点&#xff0c;或者某些时候会模仿甚至抄袭竞品网站。那么如何…

【笔记】Helm- 5 Chart模板指南-2 内置对象

内置对象 对象可以通过模板引擎传递到模板中。当然您的代码也可以传递对象。&#xff08;我们在使用with和range语句时&#xff0c;会看到示例&#xff09;。有几种方式可以在模板中创建新对象&#xff0c;比如说我们后面会看到的tuple功能。 对象可以是非常简单的&#xff1a…

C++ 类与对象(上)

目录 本节目标 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1 访问限定符 4.2 封装 5. 类的作用域 6. 类的实例化 7.类对象模型 7.1 如何计算类对象的大小 7.2 类对象的存储方式猜测 7.3 结构体内存对齐规则 8.this指针 8.1 thi…