Advertisement

Spring boot MongoDB多数据源,MongoRepository实现

阅读量:

背景

最近项目中存在模块化需求,在开发过程中需要建立多个MongoDB库来处理数据分割问题。这些文章通常可参考,其核心原理为:在Spring Boot容器中创建多份MongoDB模板实例以实现数据的分布式管理。如以下代码片段所示:

复制代码
 @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 数据库。(补充说明:可以通过 @Resource 注解引入 MongoTemplate 应用程序并将其实例命名为所需配置 bean 的名称从而创建相应的 MongoTemplate 实例)

通过MongoTemplate示例配置的basePackages指定其遵循了MongoRepository的model接口,并在应用数据库操作时被使用所设置的MongoTemplate实例。

这是最常用的Spring Boot与MongoDB跨库配置方案,在实际应用中发现该方案存在一定的局限性。具体而言,在主项目的环境中由于引入了现有配置项,在尝试使用该配置进行设置时发现:当使用MongoRepository时,默认无法按照配置文件中指定的basePackages路径来调用相关的MongoTemplate操作功能。

分析

基于前文所述的MongoDB多数据库实现中提到的核心技术是操作不同类型的MongoTemplate。其中核心在于操作不同的MongoTemplate类。通常情况下,默认会直接使用 Mongo Template 这一内置功能。然而我们也可以编写一个接口,并使其继承 MongoRepository 接口,并非必须要亲自去实现这个接口即可完成对 MongoDB 的操作。具体来说,在访问基于继承的 MongoRepository 接口时,默认我们会采用 Spring Data 框架中的 Simple.MongoRepository 类作为默认选择。值得注意的是,在这种设计模式下 Simple.MongoRepository 作为一个关键组件承担着通过调用 MongoOperations 接口来完成对 MongoDB 数据库的操作职责。而 MongoTemplate 则是定义了这一系列操作的具体方法集合,并且作为 MongoOperations 接口的一个重要实现类也理所当然地成为连接两者的核心桥梁。

思路

当使用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。

注意:

后记

基于AOP的方式能够实现Repository层的mongodb分库。然而在常规做法中,这种操作相对来说较为繁琐。因此,在构建项目时应当尽量合理规划结构安排。与在MongoTemplate bean配置basePackages时相比,AOP机制允许我们从方法层面进行更加细致的操作控制。当然这是AOP的主要优势所在。不过从数据库设计的角度来看,一个表或collection的所有操作不应该集中在同一个库中吗?

全部评论 (0)

还没有任何评论哟~