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的数据库 ...
随机推荐
- day59 pip安装django出错解决方案
在虚拟环境下,输入 pipinstall django ==2.2,安装django,可能会出现超时问题 这里的报错是网络问题,解决方案有如下三种 (1)多试几次,网络好就装上了 (2)Cmd输入 ...
- 数据可视化之DAX篇(八) DAX学习:使用VAR定义变量
https://zhuanlan.zhihu.com/p/64414205 前面介绍如何使用DAX生成日期表的时候,使用了VAR,有人留言问这个VAR怎么理解,那么这篇文章就来介绍VAR以及它的用法. ...
- Flask 基础组件(六):Session
除请求对象之外,还有一个 session 对象.它允许你在不同请求间存储特定用户的信息.它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥. 设 ...
- JS中this指向的更改
JS中this指向的更改 JavaScript 中 this 的指向问题 前面已经总结过,但在实际开中, 很多场景都需要改变 this 的指向. 现在我们讨论更改 this 指向的问题. call更改 ...
- 3dTiles 数据规范详解[4.1] b3dm瓦片二进制数据文件结构
B3dm,Batched 3D Model,成批量的三维模型的意思. 倾斜摄影数据(例如osgb).BIM数据(如rvt).传统三维模型(如obj.dae.3dMax制作的模型等),均可创建此类瓦片. ...
- 老司机带你玩转面试(2):Redis 过期策略以及缓存雪崩、击穿、穿透
前文回顾 建议前一篇文章没看过的同学先看下前面的文章: 「老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化」 过期策略 Redis 的过期策略都有哪些? 在聊这个问题之前,一定 ...
- 用Eclipse进行单元测试JUnit4
(1)在项目中引入Jar包 (2)编写需要测试的类 public class Calculator { private static int result=0; // 静态变量,用于存储运行结 ...
- OSCP Learning Notes - Buffer Overflows(1)
Introduction to Buffer Overflows Anatomy of Memory Anatomy of the Stack Fuzzing Tools: Vulnserver - ...
- Crontab定时启动Supervisor任务
1. Crontab介绍 crontab的语法规则格式: 代表意义 分钟 小时 日期 月份 周 命令 数字范围 0~59 0~23 1~31 1~12 0~7 需要执行的命令 周的数字为 0 或 7 ...
- 记录一次JSON数据处理(省市区数据)
最近在实习工作中遇到了一个需要问题:将后台返回的省市区 json 数据格式化以便前端渲染.这个问题真的是缠绕了我好几天,有思路但是思路特别模糊,今天终于解决了. 返回的数据格式如下: [ { &quo ...