springboot集成mongodb实现动态切换数据源
主要实现原理,利用spring的aop 在切入点执行db操作之前 将数据库切换:
本例子采用aop在controller进行拦截 拦截到MongoTemplate.class 切换数据源后重新放回去 ,处理完成后将相关数据源的template删除
引入mongodb相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
多数据源MultiMongoTemplate
import com.mongodb.client.MongoDatabase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate; public class MultiMongoTemplate extends MongoTemplate {
private Logger logger= LoggerFactory.getLogger(MultiMongoTemplate.class);
//用来缓存当前MongoDbFactory
private static ThreadLocal<MongoDbFactory> mongoDbFactoryThreadLocal;
public MultiMongoTemplate(MongoDbFactory mongoDbFactory){
super(mongoDbFactory);
if(mongoDbFactoryThreadLocal==null) {
mongoDbFactoryThreadLocal = new ThreadLocal<>();
}
} public void setMongoDbFactory(MongoDbFactory factory){
mongoDbFactoryThreadLocal.set(factory);
} public void removeMongoDbFactory(){
mongoDbFactoryThreadLocal.remove();
} @Override
public MongoDatabase getDb() {
return mongoDbFactoryThreadLocal.get().getDb();
}
}
aop 切片类MongoSwitch
import cn.net.topnet.topfs.dynamicdb.MultiMongoTemplate;
import com.mongodb.MongoClient;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map; @Component
@Aspect
public class MongoSwitch {
private final Logger logger = LoggerFactory.getLogger(MongoSwitch.class); @Autowired
private MongoDbFactory mongoDbFactory;
private Map<String,MongoDbFactory> templateMuliteMap=new HashMap<>();
//获取配置文件的副本集连接
@Value("${spring.data.mongodb.uri}")
private String uri; @Pointcut("execution(* cn.net.topnet.topfs.controller..*.*(..))")
public void routeMongoDB() { } @Around("routeMongoDB()")
public Object routeMongoDB(ProceedingJoinPoint joinPoint) {
Object result = null;
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); //获取需要访问的项目数据库
String dbName = request.getRequestURI().trim().substring(1);
String name = joinPoint.getSignature().getName();
Object o = joinPoint.getTarget();
Field[] fields = o.getClass().getDeclaredFields();
MultiMongoTemplate mongoTemplate = null; try {
for (Field field : fields) {
field.setAccessible(true);
Object fieldObject = field.get(o);
Class fieldclass = fieldObject.getClass();
//找到Template的变量
if (fieldclass == MongoTemplate.class || fieldclass == MultiMongoTemplate.class) {
//查找项目对应的MongFactory
SimpleMongoClientDbFactory simpleMongoClientDbFactory=(SimpleMongoClientDbFactory)templateMuliteMap.get(dbName);
//实例化
if(simpleMongoClientDbFactory==null){
//替换数据源
simpleMongoClientDbFactory = new SimpleMongoClientDbFactory(this.uri.replace("#",dbName));
templateMuliteMap.put(dbName,simpleMongoClientDbFactory);
}
//如果第一次,赋值成自定义的MongoTemplate子类
if(fieldclass==MongoTemplate.class){
mongoTemplate = new MultiMongoTemplate(simpleMongoClientDbFactory);
}else if(fieldclass==MultiMongoTemplate.class){
mongoTemplate=(MultiMongoTemplate)fieldObject;
}
//设置MongoFactory
mongoTemplate.setMongoDbFactory(simpleMongoClientDbFactory);
//重新赋值
field.set(o, mongoTemplate);
break;
}
}
try {
result = joinPoint.proceed();
//清理ThreadLocal的变量
mongoTemplate.removeMongoDbFactory();
} catch (Throwable t) {
logger.error("", t);
}
} catch (Exception e) {
logger.error("", e);
} return result;
}
}
yml配置
spring:
data:
mongodb:
uri: mongodb://bobo:bobo123@192.168.3.114:27017,192.168.3.114:27018,192.168.3.114:27019/#?connect=replicaSet&slaveOk=true&replicaSet=myrs
测试controller
@GetMapping("/{dbName}")
public void testMongoTemplate(@PathVariable("dbName") String dbName){ Query query = new Query();
query.addCriteria(Criteria.where("display").is("测试"));
// spring会将查询到的结果自动映射
Domains one = mongoTemplate.findOne(query, Domains.class); System.out.println(one);
}
springboot集成mongodb实现动态切换数据源的更多相关文章
- Springboot+Mybatis AOP注解动态切换数据源
在开发中因需求在项目中需要实现多数据源(虽然项目框架是SpringCloud,但是因其中只是单独的查询操作,觉得没必要开发一个项目,所以采用多数据源来进行实现) 1.在配置文件中创建多个数据连接配置 ...
- hibernate动态切换数据源
起因: 公司的当前产品,主要是两个项目集成的,一个是java项目,还有一个是php项目,两个项目用的是不同的数据源,但都是mysql数据库,因为java这边的开发工作已经基本完成了,而php那边任务还 ...
- 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法
相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法
一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...
- Spring + Mybatis 项目实现动态切换数据源
项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法
一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...
- Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源
深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...
- SpringBoot集成Shiro 实现动态加载权限
一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...
- Spring+Mybatis动态切换数据源
功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...
随机推荐
- mui点击蒙版点击蒙版让其不自动关闭
var mask = mui.createMask(callback);//callback为用户点击蒙版时自动执行的回调: mask.show();//显示遮罩 mask.close();//关闭遮 ...
- vue :没有全局变量的计数器
created: created () { let num = null this.mFun(num) }, methods: methods:{ mFun(m){ if (m === null) { ...
- NameBeta - 多家比价以节省咱的域名注册成本
共收录 1584 种顶级域名,汇集互联网上 29 家知名域名注册商,每日更新价格信息 有的域名还可以查出到期时间点我前往官网 NameSilo1美元优惠码:whatz
- nginx的基础学习+实战
文章目录 一.前言 二.反向代理 三.负载均衡 四.动静分离 参考视频:尚硅谷Nginx教程(2019发布) 参考链接:Windows下Nginx负载均衡实现 一.前言 Nginx (engine x ...
- [jvm] -- 垃圾收集算法篇
垃圾收集算法 标记-清除算法 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 缺点: 效率问题: 空间问题(标记清除后会产生大量不连续的碎片) 复制算法 它可以将内存分为大小相同 ...
- 题解 洛谷 P3710 【方方方的数据结构】
因为有撤销操作,所以修改操作可能会只会存在一段时间,因此把时间看作一维,被修改的序列看作一维. 可以把操作都离线下来,对于每个修改操作,就是在二维平面上对一个矩形进行修改,询问操作,就是查询单点权值. ...
- jmeter零散知识点
- shell 输出json格式的内容
对于shell脚本的输出,如果要输出json格式的内容,我们可以借助python -m json.tool命令 比如 echo '{"name":"zhangsan&qu ...
- Raid0,1,5,10,50
raid0 就是把多个硬盘合并成1个逻辑盘使用,数据读写时对各硬盘同时操作,不同硬盘写入不同数据,速度快. **最少需要2块硬盘 raid1 同时对2个硬盘读写(同样的数据).强调数据的安全性.损坏一 ...
- 官宣!AWS Athena正式可查询Apache Hudi数据集
1. 引入 Apache Hudi是一个开源的增量数据处理框架,提供了行级insert.update.upsert.delete的细粒度处理能力(Upsert表示如果数据集中存在记录就更新:否则插入) ...