zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    java7或java8新特性
    反射中,Class.forName和ClassLoader区别
    &和&&的区别
    JAVA时区问题总结
    索引失效原因及解决索引失效方法
    索引失效的7种情况
    MySQL Explain详解
    java switch
    java 生成注释文档
    spring 获取配置文件的值
  • 原文地址:https://www.cnblogs.com/kelelipeng/p/13329765.html
Copyright © 2011-2022 走看看