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的数据库 ...
随机推荐
- 记一次WPF程序带参数启动
问题:总共有两个程序.第一个程序使用Process带参数启动第二个程序. 网上一堆人都说什么重写Main入口啊 什么的.然后还一堆人跟着复制发文章.我也是醉了,简直是坑人.为何要舍近求远,直接重写AP ...
- JavaScript学习 Ⅳ
八. 批量创建对象 使用工厂方法创建对象 function creatPerson(name, age, gender='男'){ var obj = new Object(); obj.name = ...
- 双网卡bonding
网卡:计算机与外界局域网的连接是通过主机箱内插入一块网络接口板(或者是在笔记本电脑中插入一块PCMCIA卡).网络接口板又称为通信适配器或网络适配器(adapter)或网络接口卡NIC(Network ...
- gvim使用总结
我的gvim配置 set nocompatible " 关闭vi兼容 " 显示相关 set go= set number set cursorline set nowrap set ...
- Spring常见问题大全
Spring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring ...
- 使用nvm安装node,运行node报错 node: command not found
1. 使用nvm安装node之后,直接运行node命令会报错 node: command not found 需要使用nvm ls 查询一下当前使用的安装的node版本,然后使用node use 版 ...
- 云原生时代高性能Java框架—Quarkus(一)
--- Quarkus&GraalVM介绍.创建并启动第一个项目 Quarkus系列博文 Quarkus&GraalVM介绍.创建并启动第一个项目 构建Quarkus本地镜像.容器化部 ...
- JAVA各种OOM代码样例及解决方法
周末了,觉得我还有很多作业没有写,针对目前大家对OOM的类型不太熟悉,那么我们来总结一下各种OOM出现的情况以及解决方法. 我们把各种OOM的情况列出来,然后逐一进行代码编写复现和提供解决方法. 1. ...
- javascript实战 : 简单的颜色渐变
HTML <div id="color"></div> CSS .item{ display:inline-block; margin:10px; widt ...
- IDEA 格式化代码快捷键
一般都是:Ctrl+Alt+L 如果未格式化的话,可能与以下软件的快捷键冲突了: QQ 网易云 也可能是其他的快捷键组合,具体可查看工具栏Code->Reformat Code: 也可重新设置i ...