SpringBoot运行时动态添加数据源
此方案适用于解决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运行时动态添加数据源的更多相关文章
- mybatis JdbcTypeInterceptor - 运行时自动添加 jdbcType 属性
上代码: package tk.mybatis.plugin; import org.apache.ibatis.executor.ErrorContext; import org.apache.ib ...
- 使用javassist运行时动态重新加载java类及其他替换选择
在不少的情况下,我们需要对生产中的系统进行问题排查,但是又不能重启应用,java应用不同于数据库的存储过程,至少到目前为止,还不能原生的支持随时进行编译替换,从这种角度来说,数据库比java的动态性要 ...
- 运行时动态库:not found 及介绍-linux的-Wl,-rpath命令
---此文章同步自我的CSDN博客--- 一.运行时动态库:not found 今天在使用linux编写c/c++程序时,需要用到第三方的动态库文件.刚开始编译完后,运行提示找不到动态库文件.我就 ...
- 动态添加数据源,根据用户登录切换数据库.编程式Spring事务.
根据用户注册,系统自动创建私有数据库,用户登录,动态添加数据源到Spring数据路由,Session超时删除数据源 好处:当数据量大的时候,类似水平切割效果,效率会高一些 坏处:数据源切换,Sprin ...
- 解决 Retrofit 多 BaseUrl 及运行时动态改变 BaseUrl ?
原文地址: juejin.im/post/597856- 解决Retrofit多BaseUrl及运行时动态改变BaseUrl(一) 解决Retrofit多BaseUrl及运行时动态改变BaseUrl( ...
- 自己动手实现springboot运行时执行java源码(运行时编译、加载、注册bean、调用)
看来断点.单步调试还不够硬核,根本没多少人看,这次再来个硬核的.依然是由于apaas平台越来越流行了,如果apaas平台选择了java语言作为平台内的业务代码,那么不仅仅面临着IDE外的断点.单步调试 ...
- .NET6运行时动态更新限流阈值
昨天博客园撑不住流量又崩溃了,很巧正在编写这篇文章,于是产生一个假想:如果博客园用上我这个限流组件会怎么样呢? 用户会收到几个429错误,并且多刷新几次就看到了内容,不会出现完全不可用. 还可以降低查 ...
- C# 在运行时动态创建类型
C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...
- LINQ to SQL 运行时动态构建查询条件
在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...
随机推荐
- 模板汇总——Tarjian
1. 单向边 + 新图建边 int belong[N], dfn[N], low[N], now_time, scc_cnt; stack<int> s; void dfs(int u) ...
- NOIP 2005 等价表达式 题解
题意 给一个表达式然后再给n个表达式,判断是否等价 一道大模拟题,将a带为数,并且取模防止溢出 #include<bits/stdc++.h> using namespace std; c ...
- 手工释放服务器的swap分区缓存
时间 恢复时间 状态 信息 主机 问题 • 严重性 持续时间 确认 动作 2019-03-21 20:29:30 09:51:30 -ai-代理 Lack of free sw ...
- Vue兄弟组件通信
Vue兄弟组件通信之借助中央事件总线 下载链接:https://www.yinxiangit.com 其实要实现兄弟组件通信,就算是通过父子组件通信的方式也是可以达到的,如 子 ——>父——&g ...
- 树莓派4B 安装CentOS
刚入手了一个树莓派4B替换掉旧的3B搭Nas.吐槽下3B的网卡和USB速度真的太慢. 虽然官方推荐的是Debina,由于习惯了CentOS不想增加学习成本,我还是决定用CentOS. 镜像下载地址:h ...
- springmvc项目中的中文乱码的解决及未生效解决
情景: springmvc项目中,在控制台输出时中文乱码,在web网页中正常. 解决方法: 在web.xml中添加如下代码: <!-- 中文乱码解决 --> <filter> ...
- 个人网站(sysoft.net.cn)被k,公司名都搜索不出来了,怎么办?
今年上班后,好2019年3月初,上班后(年前大病一场 ,两个月没维护网站),发现公司网站所有收录都掉了,搜索公司名都不不到了,宝宝真是惊呆了. 有些人说是百度出了故障,有人说是百度算法. 说句 ...
- TestNG(十二) 参数化测试
<?xml version="1.0" encoding="utf-8" ?> <suite name = "parameter&q ...
- OAuth2.0摘要
一.简介 不使用oauth2.0协议,资源所有者直接给需要使用资源的第三方应用共享凭据时,有这些问题: 需要直接共享给第三方应用凭据 需要服务器支持密码身份验证 凭据的访问权限过大,失去对访问时间和范 ...
- 【linux】【Zookeeper】Centos7安装Zookeeper-3.5.5
一 .下载zookeeper wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.5/apache-zookeeper-3.5.5 ...