此方案适用于解决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. 计蒜客 ACM训练联盟周赛 第一场 Christina式方格取数 思维

    助手Christina发明了一种方格取数的新玩法:在n*m的方格棋盘里,每个格子里写一个数.两个人轮流给格子染色,直到所有格子都染了色.在所有格子染色完后,计算双方的分数.对于任意两个相邻(即有公共边 ...

  2. CF990B Micro-World 贪心 第十六

    Micro-World time limit per test 2 seconds memory limit per test 256 megabytes input standard input o ...

  3. 第四篇 跟踪过程以及openvslam中的相关实现详解

    在成功初始化之后,会创建地图以及局部地图. 创建地图 在初始化正常过后,紧接着会创建地图 // src/openvslam/module/initializer.cc:67 // create new ...

  4. 编写一个函数来反转某个二进制型里的字节顺序(erlang)

    reverse_byte(<<>>) -> <<>>; reverse_byte(<<Header:8, Tail/bits>& ...

  5. 更换SVN项目资源库目录出现的问题

    今天在做SVN资源库管理时出现了如下问题: 因为当时把资源库地址写错了,所以想换个资源库,所以先断开资源库 然后我重新导入新的资源库位置: 于是就出现了这种问题: 其实这个问题困扰我好久了之前一直放过 ...

  6. Python(Head First)学习笔记:四

    4 持久存储:文件存储.读写 数据保存到文件:在学习的过程中出现了一个问题,老是报一个错:SyntaxError: invalid syntax: 这个是语法错误,后来搜了下才知道是python2.7 ...

  7. OpenGl读取导入3D模型并且添加鼠标移动旋转显示

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...

  8. 华为Quidway S5700开启SNMP协议

    开启SNMP协议通过Console口登录主要用于交换机第一次上电或者本地配置.或者无法通过远程访问时,可通过Console口登录.如何才能通过Console口登录交换机呢?在配置通过Console口配 ...

  9. Azure虚拟机时间同步问题

    场景描述:在Azure上新创建虚拟机默认是UTC时区的,因为业务在国内,所以要修改在CST注:协调世界时(英语:Coordinated Universal Time,法语:Temps Universe ...

  10. maven下载jar包源码配置

    两个依赖,就想下mail的源码包,因该怎么 <dependencies> <dependency> <groupId>javax.mail</groupId& ...