|
主要实现原理,利用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);
}
来源:https://www.cnblogs.com/jiawen010/p/12664494.html |