zoukankan      html  css  js  c++  java
  • 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);
        }
  • 相关阅读:
    ubuntu中安装monodevelop
    谈谈asp.net中的<% %>,<%= %>,<%# %><%$ %>的使用
    asp.net中的App_GlobalResources和App_LocalResources使用
    cisco通过控制口或者通过远程配置交换机
    匿名函数
    迭代器生成器
    闭包函数,装饰器
    函数之对象和名称空间与作用域
    函数
    文件操作
  • 原文地址:https://www.cnblogs.com/jiawen010/p/12664494.html
Copyright © 2011-2022 走看看