此方案适用于解决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. CF980B Marlin 构造 思维 二十四

    Marlin time limit per test 1 second memory limit per test 256 megabytes input standard input output ...

  2. hdu1576 扩展欧几里德 A/B

    A/B Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  3. MultipartFile 获取上传TXT文件字数

    @ResponseBody @RequestMapping(value = "/addImgForDynamic")//(发布动态) public Map addImgForDyn ...

  4. Java基础语法(总结篇)

    关键字&标识符 关键字的概念与特征 概念:Java关键字是事先定义好的对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名.方法名.类名.包名和 ...

  5. FreeSql (三十)读写分离

    FreeSql 支持数据库读写分离,本功能是客户端的读写分离行为,数据库服务器该怎么配置仍然那样配置,不受本功能影响,为了方便描术后面讲到的[读写分离]都是指客户端的功能支持. 各种数据库的读写方案不 ...

  6. Spring Boot 配置文件和命令行配置

    Spring Boot 属于约定大于配置,就是说 Spring Boot 推荐不做配置,很多都是默认配置,但如果想要配置系统,使得软件符合业务定义,Spring Boot 可以通过多种方式进行配置. ...

  7. 去掉Myeclipse对JS等文件的验证

    在用Myeclipse导入新工程或在写代码时,最郁闷的就是它对js,jsp,html的验证太严格了,有时会呈现一个红叉或者一个黄色的感慨号,一运行就报Cannot return from outsid ...

  8. Sqoop介绍、安装与操作

    搭建环境 部署节点操作系统为CentOS,防火墙和SElinux禁用,创建了一个shiyanlou用户并在系统根目录下创建/app目录,用于存放 Hadoop等组件运行包.因为该目录用于安装hadoo ...

  9. Linux之正则表达式grep

    真好!

  10. 02 (H5*) Vue第二天

    目录: 1:全局过滤器的使用 2:局部过滤器 3:自定义键盘码 4:自定义指令 5:自定义私有指令 6:Vue生命周期. 7:网络请求 1:全局过滤器的使用 Vue.filter("msgF ...