此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!!

一、多数据源应用场景:

1.配置文件配置多数据源,如默认数据源:master,数据源1:salve1...,运行时动态切换已配置的数据源(master、salve1互相切换),无法在运行时动态添加配置文件中未配置的数据源。

2.配置一个默认数据源,运行时动态添加新数据源使用(本博客适用于此场景)

二、解决方案:

Spring提供了AbstractRoutingDataSource用于动态路由数据源,第一种场景继承AbstractRoutingDataSource类并覆写其protected abstract Object determineCurrentLookupKey()即可;

而第二种场景我们直接覆写protected DataSource determineTargetDataSource方法即可。原理可看下AbstractRoutingDataSource对应源码,比较简单,不做赘述。

直接上干货:

import com.yaoshun.util.spring.SpringUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* <p>使用步骤:</p>
* <blockquote><pre>
* DynamicDataSource.dataSourcesMap.put(dataSourceKey, druidDataSource);
* DynamicDataSource.setDataSource(dataSourceKey);
* 调用业务代码</i>
* DynamicDataSource.clear();
* </pre></blockquote>
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> dataSourceKey = ThreadLocal.withInitial(() -> "defaultDataSource"); public static Map<Object, Object> dataSourcesMap = new ConcurrentHashMap<>(10); static {
dataSourcesMap.put("defaultDataSource", SpringUtils.getBean("defaultDataSource"));
} @Override
protected Object determineCurrentLookupKey() {
return DynamicDataSource.dataSourceKey.get();
} public static void setDataSource(String dataSource) {
DynamicDataSource.dataSourceKey.set(dataSource);
DynamicDataSource dynamicDataSource = (DynamicDataSource) SpringUtils.getBean("dataSource");
dynamicDataSource.afterPropertiesSet();
} public static String getDataSource() {
return DynamicDataSource.dataSourceKey.get();
} public static void clear() {
DynamicDataSource.dataSourceKey.remove();
}
}
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource; @Configuration
public class DataSourceConfig { @Bean
@ConfigurationProperties("spring.datasource.druid")
public DataSource defaultDataSource() {
return DruidDataSourceBuilder.create().build();
} @Bean
@Primary
@DependsOn({"springUtils", "defaultDataSource"})
public DynamicDataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(DynamicDataSource.dataSourcesMap);
return dynamicDataSource;
}
}

使用时直接调用DynamicDataSource.setDataSource(DataSource dataSource)方法即可,使用完后调用DynamicDataSource.clear()防止内存泄漏并重置默认数据源。

附上详细使用方法:

        DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://localhost:3306/sys?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&useAffectedRows=true");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
DynamicDataSource.dataSourcesMap.put("dbkey", druidDataSource);
DynamicDataSource.setDataSource("dbkey");
此时数据源已切换到druidDataSource ,调用自己的业务方法即可。
使用完后调用DynamicDataSource.clear();重置为默认数据源。

附上工具类SpringUtils :

import lombok.Getter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component; @Component
public final class SpringUtils implements ApplicationContextAware { @Getter
private static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
} public static <T> T getBean(Class<T> clazz) {
return SpringUtils.applicationContext.getBean(clazz);
} public static Object getBean(String name) {
return SpringUtils.applicationContext.getBean(name);
} public static String getProperty(String key) {
return SpringUtils.applicationContext.getEnvironment().getProperty(key);
}
}

SpringBoot运行时动态添加数据源的更多相关文章

  1. mybatis JdbcTypeInterceptor - 运行时自动添加 jdbcType 属性

    上代码: package tk.mybatis.plugin; import org.apache.ibatis.executor.ErrorContext; import org.apache.ib ...

  2. 使用javassist运行时动态重新加载java类及其他替换选择

    在不少的情况下,我们需要对生产中的系统进行问题排查,但是又不能重启应用,java应用不同于数据库的存储过程,至少到目前为止,还不能原生的支持随时进行编译替换,从这种角度来说,数据库比java的动态性要 ...

  3. 运行时动态库:not found 及介绍-linux的-Wl,-rpath命令

    ---此文章同步自我的CSDN博客--- 一.运行时动态库:not found   今天在使用linux编写c/c++程序时,需要用到第三方的动态库文件.刚开始编译完后,运行提示找不到动态库文件.我就 ...

  4. 动态添加数据源,根据用户登录切换数据库.编程式Spring事务.

    根据用户注册,系统自动创建私有数据库,用户登录,动态添加数据源到Spring数据路由,Session超时删除数据源 好处:当数据量大的时候,类似水平切割效果,效率会高一些 坏处:数据源切换,Sprin ...

  5. 解决 Retrofit 多 BaseUrl 及运行时动态改变 BaseUrl ?

    原文地址: juejin.im/post/597856- 解决Retrofit多BaseUrl及运行时动态改变BaseUrl(一) 解决Retrofit多BaseUrl及运行时动态改变BaseUrl( ...

  6. 自己动手实现springboot运行时执行java源码(运行时编译、加载、注册bean、调用)

    看来断点.单步调试还不够硬核,根本没多少人看,这次再来个硬核的.依然是由于apaas平台越来越流行了,如果apaas平台选择了java语言作为平台内的业务代码,那么不仅仅面临着IDE外的断点.单步调试 ...

  7. .NET6运行时动态更新限流阈值

    昨天博客园撑不住流量又崩溃了,很巧正在编写这篇文章,于是产生一个假想:如果博客园用上我这个限流组件会怎么样呢? 用户会收到几个429错误,并且多刷新几次就看到了内容,不会出现完全不可用. 还可以降低查 ...

  8. C# 在运行时动态创建类型

    C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...

  9. LINQ to SQL 运行时动态构建查询条件

    在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...

随机推荐

  1. poj 1417 True Liars(并查集+背包dp)

    题目链接:http://poj.org/problem?id=1417 题意:就是给出n个问题有p1个好人,p2个坏人,问x,y是否是同类人,坏人只会说谎话,好人只会说实话. 最后问能否得出全部的好人 ...

  2. 【第二十二篇】从客户端中检测到有潜在危险的 Request.Form 值

    提交数据的时候  用js的方法   escape(富文本框的值)    例:escape(UM.getEditor('Content').getContent()); 取值的时候   unescape ...

  3. Stanford公开课《编译原理》学习笔记(1~4课)

    目录 一. 编译的基本流程 二. Lexical Analysis(词法分析阶段) 2.1 Lexical Specification(分词原则) 2.2 Finite Automata (典型分词算 ...

  4. Python—字符串和常用数据结构

    目录 1. 字符串 2. 列表 2.1 列表的增删改查 2.2 列表的切片和排序 2.3 生成式语法 3. 元组 4.集合 5. 字典 5.1 字典的增删改查 5.2 字典的常见操作 序言:这一章我们 ...

  5. 零基础快速入门Java的秘诀

    刚开始学习Java时要端正自己的学习的目标和态度,明确学习Java基础重点要做什么. 首先第一点,Java基础的学习,基础很重要,基础好地基牢,才能爬的高! 大家要从以下4个方向努力: 代码能力:一定 ...

  6. JavaScript之深入函数(二)

    上一篇我们主要讲解了函数的执行过程和原理,本篇我们将介绍函数的另外两个特殊表现:闭包和立即执行函数. 一 闭包 1,  闭包的形成 之前我们提到,函数执行完毕,马上就会销毁自己的AO对象.但是如果遇到 ...

  7. vsftpd上传文件大小为0(主动模式)

    最近在搞VSFTPD+Nginx结合,但是发现上传文件大小总是为0, 由于最开始在搞的时候不知道主动模式和被动模式到底是什么鬼东西,所以遇到问题根本找不到根的原因,遇到问题只是乱搜,好像是解决了问题, ...

  8. 第六届蓝桥杯java b组第四题

    第四题 两个整数做除法,有时会产生循环小数,其循环部分称为:循环节. 比如,11/13=6=>0.846153846153….. 其循环节为[846153] 共有6位. 下面的方法,可以求出循环 ...

  9. Scrapy项目 - 实现百度贴吧帖子主题及图片爬取的爬虫设计

    要求编写的程序可获取任一贴吧页面中的帖子链接,并爬取贴子中用户发表的图片,在此过程中使用user agent 伪装和轮换,解决爬虫ip被目标网站封禁的问题.熟悉掌握基本的网页和url分析,同时能灵活使 ...

  10. Maven 梳理 -eclipse中创建Maven的web项目

    已验证成功: 1.创建Maven的Web工程 新建Maven工程:File -> New -> Maven Project,具体如下所示: 点击Next进入下述页面,下方的窗口是我们选择所 ...