spring-data-mongodb多數據庫訪問實現

最近公司項目須要支持multi-tenancy,每一個tenant數據庫地址不一樣,需求就是修改配置文件,添加或者刪除數據庫配置,重啓系統後就能夠完成,不須要額外修改代碼。html

網上搜索了一下,基本上都是將配置寫在了代碼裏了,例如:http://www.devzxd.top/2017/06...,不能動態增減數據庫配置,而且對不一樣的數據庫建立不一樣的Repository。繼續Google以後,在github上找到一個例子multi-tenant-spring-mongodb,看了一下代碼,仍是不符合需求。沒辦法,只能看代碼,調試來看看本身能不能實現這個需求了。java

那spring-data-mongodb怎麼來完成數據庫的訪問的呢?核心類是SimpleMongoRepository,而mongoOperations變量纔是完成訪問的關鍵,而這個mongoOperations其實就是mongoTemplate。那就意味着若是咱們可以動態改變這個mongoTemplate的值就能夠切換數據庫了,竊喜。git

解決的方法有了,可是如何實現呢?庫並無提供相似Hibernate那樣的MultiTenantConnectionProviderCurrentTenantIdentifierResolver來幫助咱們實現。既然spring是經過AOP和Proxy來完成功能的調用的,咱們彷佛也能夠這麼玩。github

  1. 咱們要對全部的Repository方法的訪問建立一個PointCut,這樣咱們就能夠在訪問以前搞事情了。
  2. 利用反射拿到joinPoint的target,而後調用用AopProxyUtils.getSingletonTarget(target)取到最終的SimpleMongoRepository實例。
  3. 經過反射設置mongoOperations的值。

代碼以下:spring

@Repository
public interface WidgetDataRepository extends MongoRepository<WidgetData, String> {
}
// 注意:線程不安全!!!
@Around("execution(* com.example.demo.dao.mongo.MongoWidgetDataRepo.*(..))")
public Object doSwitch(ProceedingJoinPoint joinPoint) throws Throwable {
    // 拿到咱們須要的tenant
    String tenant = (String) RequestContextHolder.currentRequestAttributes().getAttribute("tenant", SCOPE_REQUEST);
    tenant = tenant == null ? "test" : tenant;
    
    // 經過反射獲取到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,並往裏面填入值
    Object singletonTarget = AopProxyUtils.getSingletonTarget(target);
    Field mongoOperationsField = singletonTarget.getClass().getDeclaredField("mongoOperations");
    mongoOperationsField.setAccessible(true);
    mongoOperationsField.set(singletonTarget, ac.getBean("mongoTemplate" + tenant));

    return joinPoint.proceed();
}

這樣咱們就能夠完成數據庫的切換了,能夠利用spring-data-mongodb,儘量的少些模板代碼。mongodb

相關文章
相關標籤/搜索