南方老张爱生活 發表於 2020-4-9 08:55:00

springboot集成mongodb实现动态切换数据源

<p>主要实现原理,利用spring的aop 在切入点执行db操作之前 将数据库切换:</p>
<p>本例子采用aop在controller进行拦截 拦截到MongoTemplate.class 切换数据源后重新放回去 ,处理完成后将相关数据源的template删除</p>
<p>&nbsp;</p>
<p>引入mongodb相关依赖</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-data-mongodb<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">引入AOP依赖</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-boot-starter-aop<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<pre>多数据源MultiMongoTemplate</pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.mongodb.client.MongoDatabase;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.slf4j.Logger;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.slf4j.LoggerFactory;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.data.mongodb.MongoDbFactory;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.data.mongodb.core.MongoTemplate;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MultiMongoTemplate <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> MongoTemplate {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> Logger logger= LoggerFactory.getLogger(MultiMongoTemplate.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用来缓存当前MongoDbFactory</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> ThreadLocal&lt;MongoDbFactory&gt;<span style="color: rgba(0, 0, 0, 1)"> mongoDbFactoryThreadLocal;
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MultiMongoTemplate(MongoDbFactory mongoDbFactory){
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">(mongoDbFactory);
      </span><span style="color: rgba(0, 0, 255, 1)">if</span>(mongoDbFactoryThreadLocal==<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
            mongoDbFactoryThreadLocal </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ThreadLocal&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
      }
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setMongoDbFactory(MongoDbFactory factory){
      mongoDbFactoryThreadLocal.set(factory);
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> removeMongoDbFactory(){
      mongoDbFactoryThreadLocal.remove();
    }

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MongoDatabase getDb() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> mongoDbFactoryThreadLocal.get().getDb();
    }
}</span></pre>
</div>
<p>aop 切片类MongoSwitch</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> cn.net.topnet.topfs.dynamicdb.MultiMongoTemplate;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.mongodb.MongoClient;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.aspectj.lang.ProceedingJoinPoint;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.aspectj.lang.annotation.Around;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.aspectj.lang.annotation.Aspect;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.aspectj.lang.annotation.Pointcut;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.slf4j.Logger;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.slf4j.LoggerFactory;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.beans.factory.annotation.Autowired;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.beans.factory.annotation.Value;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.data.mongodb.MongoDbFactory;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.data.mongodb.core.MongoTemplate;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.data.mongodb.core.SimpleMongoDbFactory;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.stereotype.Component;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.web.context.request.RequestContextHolder;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.web.context.request.ServletRequestAttributes;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.servlet.http.HttpServletRequest;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.lang.reflect.Field;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.HashMap;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Map;

@Component
@Aspect
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MongoSwitch {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Logger logger = LoggerFactory.getLogger(MongoSwitch.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

    @Autowired
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> MongoDbFactory mongoDbFactory;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> Map&lt;String,MongoDbFactory&gt; templateMuliteMap=<span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取配置文件的副本集连接</span>
    @Value("${spring.data.mongodb.uri}"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String uri;

    @Pointcut(</span>"execution(* cn.net.topnet.topfs.controller..*.*(..))"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> routeMongoDB() {

    }

    @Around(</span>"routeMongoDB()"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Object routeMongoDB(ProceedingJoinPoint joinPoint) {
      Object result </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
      HttpServletRequest request </span>=<span style="color: rgba(0, 0, 0, 1)"> ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取需要访问的项目数据库</span>
      String dbName = request.getRequestURI().trim().substring(1<span style="color: rgba(0, 0, 0, 1)">);
      String name </span>=<span style="color: rgba(0, 0, 0, 1)"> joinPoint.getSignature().getName();
      Object o </span>=<span style="color: rgba(0, 0, 0, 1)"> joinPoint.getTarget();
      Field[] fields </span>=<span style="color: rgba(0, 0, 0, 1)"> o.getClass().getDeclaredFields();
      MultiMongoTemplate mongoTemplate </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;

      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Field field : fields) {
                field.setAccessible(</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
                Object fieldObject </span>=<span style="color: rgba(0, 0, 0, 1)"> field.get(o);
                Class fieldclass </span>=<span style="color: rgba(0, 0, 0, 1)"> fieldObject.getClass();
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">找到Template的变量</span>
                <span style="color: rgba(0, 0, 255, 1)">if</span> (fieldclass == MongoTemplate.<span style="color: rgba(0, 0, 255, 1)">class</span> || fieldclass == MultiMongoTemplate.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">) {
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">查找项目对应的MongFactory</span>
                  SimpleMongoClientDbFactory simpleMongoClientDbFactory=<span style="color: rgba(0, 0, 0, 1)">(SimpleMongoClientDbFactory)templateMuliteMap.get(dbName);
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实例化</span>
                  <span style="color: rgba(0, 0, 255, 1)">if</span>(simpleMongoClientDbFactory==<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){<br>               <span style="color: rgba(153, 204, 0, 1)"> //替换数据源</span>
                        simpleMongoClientDbFactory </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> SimpleMongoClientDbFactory(<span style="color: rgba(0, 0, 255, 1)">this</span>.uri.replace("#"<span style="color: rgba(0, 0, 0, 1)">,dbName));
                        templateMuliteMap.put(dbName,simpleMongoClientDbFactory);
                  }
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果第一次,赋值成自定义的MongoTemplate子类</span>
                  <span style="color: rgba(0, 0, 255, 1)">if</span>(fieldclass==MongoTemplate.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">){
                        mongoTemplate </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MultiMongoTemplate(simpleMongoClientDbFactory);
                  }</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(fieldclass==MultiMongoTemplate.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">){
                        mongoTemplate</span>=<span style="color: rgba(0, 0, 0, 1)">(MultiMongoTemplate)fieldObject;
                  }
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置MongoFactory</span>
<span style="color: rgba(0, 0, 0, 1)">                  mongoTemplate.setMongoDbFactory(simpleMongoClientDbFactory);
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">重新赋值</span>
<span style="color: rgba(0, 0, 0, 1)">                  field.set(o, mongoTemplate);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                result </span>=<span style="color: rgba(0, 0, 0, 1)"> joinPoint.proceed();
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">清理ThreadLocal的变量</span>
<span style="color: rgba(0, 0, 0, 1)">                mongoTemplate.removeMongoDbFactory();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Throwable t) {
                logger.error(</span>""<span style="color: rgba(0, 0, 0, 1)">, t);
            }
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
            logger.error(</span>""<span style="color: rgba(0, 0, 0, 1)">, e);
      }

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
    }
}</span></pre>
</div>
<p>yml配置</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">spring:
data:
    mongodb:
      uri: mongodb:</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">bobo:bobo123@192.168.3.114:27017,192.168.3.114:27018,192.168.3.114:27019/#?connect=replicaSet&amp;slaveOk=true&amp;replicaSet=myrs</span></pre>
</div>
<p>测试controller</p>
<div class="cnblogs_code">
<pre>    @GetMapping("/{dbName}"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 255, 1)">void</span> testMongoTemplate(@PathVariable("dbName"<span style="color: rgba(0, 0, 0, 1)">) String dbName){

      Query query </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Query();
      query.addCriteria(Criteria.where(</span>"display").is("测试"<span style="color: rgba(0, 0, 0, 1)">));
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> spring会将查询到的结果自动映射</span>
      Domains one = mongoTemplate.findOne(query, Domains.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

      System.out.println(one);
    }</span></pre>
</div>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/jiawen010/p/12664494.html
頁: [1]
查看完整版本: springboot集成mongodb实现动态切换数据源