Spring boot MongoDB多數據源,MongoRepository實現


https://blog.csdn.net/qq_35124119/article/details/83210772


背景
        最近項目中有需求,需要多個mongo庫,分割數據。網上有很多文章可參考,其原理是:在Spring 容器中實例化多個MongoTemplate,代碼示例:

@Configuration
@EnableMongoRepositories(basePackages = {"com.sunliangliang.service.basic"}, mongoTemplateRef = "basicMongoTemplate")
@ConfigurationProperties(prefix = "basic.mongodb")
public class BasicMongoConfigure extends AbstractMongoConfigure {
@Override
@Bean(name = "basicMongoTemplate")
public MongoTemplate getMongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

使用方式:

1.使用時通過@Autowired 和@Qualifier注入MongoTemplate實例以操作不同的mongo數據庫(PS:可使用@Resource注解,引入MongoTemplate 並為其實例命名為所需的已配置的bean名稱,而引入相對應的MongoTemplate實例)

2.通過MongoTemplate示例配置的basePackages指定繼承了MongoRepository的model接口,在操作數據庫時,使用所配置的MongoTemplate實例,以操作不同的數據庫。

這是最常見的Springboot Mongo多數據配置方法,但是項目中主項目因引入的子項目里已有配置,導致在主項目中MongoTemplate配置無效,MongoRepository無法按配置的basePackages路徑使用對應的MongoTemplate操作mongo庫。

分析
         前述的實現mongo多數據庫,核心是操作不同的MongoTemplate。除了直接使用MongoTemplate,我們通常會寫一個接口繼承MongoRepository接口,並且不需要實現該接口就可操作數據庫。實際上在使用繼承的MongoRepository接口的業務接口訪問mongo時,使用的是SpringData的SimpleMongoRepository類的實例來操作數據庫,而SimpleMongoRepository的一個非常重要的Filed是MongoOperations接口,而MongoTemplate正是MongoOperations的實現。SimpleMongoRepository也正是使用MongoOperations操作mongo數據庫的。

思路
      在SimpleMongoRepository操作數據庫時,動態的修改其MongoOperations的值,即MongoTemplate。所以Spring AOP出場了。

解決辦法
1.為項目引入Spring AOP

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.編寫AOP代碼

package com.mongo;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

import java.lang.reflect.Field;

/**
* 通過AOP操作,動態更改更改mongo的repository層mongoTemplate<br/>
* 以實現mongo分庫
*
* @author RangoLan
* @desciption
* @date Created in 2018/10/17 15:20
*/
@Aspect
@Component
public class RepositoryAop {
@Autowired
WebApplicationContext context;


@Around("execution(* com.mongo.basic..*.*(..))")
public Object setMongoOperations(ProceedingJoinPoint joinPoint) throws Throwable {
setMongoTemplate4Repository(joinPoint, (MongoTemplate) context.getBean(AdminConfiguration.MONGO_ADMIN));

return joinPoint.proceed();
}

private void setMongoTemplate4Repository(ProceedingJoinPoint joinPoint, MongoTemplate template) throws NoSuchFieldException, IllegalAccessException {
// 通過反射獲取到target
Field methodInvocationField = joinPoint.getClass().getDeclaredField("methodInvocation");
methodInvocationField.setAccessible(true);
ReflectiveMethodInvocation o = (ReflectiveMethodInvocation) methodInvocationField.get(joinPoint);

Field targetField = o.getClass().getDeclaredField("target");
targetField.setAccessible(true);
Object target = targetField.get(o);

// 獲得SimpleMongoRepository,並往里面填入指定mongoTemplate
Object singletonTarget = AopProxyUtils.getSingletonTarget(target);
Field mongoOperationsField = singletonTarget.getClass().getDeclaredField("mongoOperations");
mongoOperationsField.setAccessible(true);
mongoOperationsField.set(singletonTarget, template);
}


}
單元測試OK。

注意:  由於SimpleMongoRepository在Spring容器中為單例,aop切點代碼執行后,SimpleMongoRepository的MongoOperations已更改,其他未配置切點的Repository在操作mongo時,數據庫會混亂。所以應該在AOP中明確配置各Repository所使用的MongoTemplate。

 
后記
         AOP方式實現,可實現Repository層的mongodb分庫,但是相較於常規做法,還是比較麻煩一點,建議構建項目時結構應盡量合理些。相較於配置MongoTemplate bean時指定basePackages,AOP可做到方法級控制,當然這是AOP的優點,但是對於數據庫來說,一個表或者collection的所有操作不該是在同一個庫么?
————————————————
 
原文鏈接:https://blog.csdn.net/qq_35124119/article/details/83210772


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM