springboot配置mongo多数据源方案

技术本质为制作多个mongo上下文,利用切面,在不同注解切点时切换上下文,达到多数据源的效果,以下为具体实现方案

一、修改配置文件的mongo配置方式

mongo:
  datasource:
    dblist:
      - uri: mongodb://{user}:{pwd}@{ip}:{port}/{database}?authSource=admin
        database: discover_center #对应MongoSwitch注解的值
      - uri: mongodb://{user}:{pwd}@{ip}:{port}/{database}?authSource=admin
        database: terminal_data #对应MongoSwitch注解的值

二、启动类上增加配置扫描注解@ConfigurationPropertiesScan

@SpringBootApplication
@ConfigurationPropertiesScan
@EnableDiscoveryClient
public class FalconDataCollectApplication {

    public static void main(String[] args) {
        SpringApplication.run(FalconDataCollectApplication.class, args);
    }

}

三、增加mongo配置读取类MongoListProperties

@Data
@ConfigurationProperties(prefix = "mongo.datasource")
public class MongoListProperties {
    private List<MongoList> dblist;

    @Data
    public static class MongoList {
    private String uri;
    private String database;
    }
}

四、编写mongo上下文

@Component
public class MongoDbContext {
    private static final Map<String, MongoDatabaseFactory> MONGO_CLIENT_DB_FACTORY_MAP = new HashMap<>();
    private static final ThreadLocal<MongoDatabaseFactory> MONGO_DB_FACTORY_THREAD_LOCAL = new ThreadLocal<>();
    @Resource
    MongoListProperties mongoListProperties;

    public static MongoDatabaseFactory getMongoDbFactory() {
        return MONGO_DB_FACTORY_THREAD_LOCAL.get();
    }

    public static void setMongoDbFactory(String name) {
        MONGO_DB_FACTORY_THREAD_LOCAL.set(MONGO_CLIENT_DB_FACTORY_MAP.get(name));
    }

    public static void removeMongoDbFactory() {
        MONGO_DB_FACTORY_THREAD_LOCAL.remove();
    }

    @PostConstruct
    public void afterPropertiesSet() {
        if (!CollectionUtils.isEmpty(mongoListProperties.getDblist())) {

            mongoListProperties.getDblist().forEach(info->{
                MONGO_CLIENT_DB_FACTORY_MAP.put(info.getDatabase(),new SimpleMongoClientDatabaseFactory(info.getUri()));
            });
        }
    }
    @Bean(name = "mongoTemplate")
    public MultiMongoTemplate dynamicMongoTemplate() {
        Iterator<MongoDatabaseFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
        return new MultiMongoTemplate(iterator.next());
    }

    @Bean(name = "mongoDbFactory")
    public MongoDatabaseFactory mongoDbFactory() {
        Iterator<MongoDatabaseFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
        return iterator.next();
    }
}

五、增加MongoSwitch注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MongoSwitch {
    /**
     * mongo数据库名称
     *
     * @return
     */
    String value() default "";
}

六、增加切面

@Component
@Aspect
@Order(value = -99)
@Slf4j
public class MongoDbSwitch {
    @Pointcut("@annotation(com.vcolco.falcon.config.mongo.MongoSwitch)")
    public void mongoSwitch() {}

    @Before("mongoSwitch()")
    public void before(JoinPoint point) {
        try {
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            Method method = point.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            MongoSwitch mongoSwitch = method.getAnnotation(MongoSwitch.class);
            MongoDbContext.setMongoDbFactory(mongoSwitch.value());
        } catch (Exception e) {
            log.error("==========>前置mongo数据源切换异常", e);
        }
    }

    @After("mongoSwitch()")
    public void after(JoinPoint point) {
        try {
            MongoDbContext.removeMongoDbFactory();
        } catch (Exception e) {
            log.error("==========>后置mongo数据源切换异常", e);
        }
    }
}

七、动态mongo数据源

public class MultiMongoTemplate extends MongoTemplate {
    public MultiMongoTemplate(MongoDatabaseFactory mongoDbFactory) {
        super(mongoDbFactory);
    }

    @Override
    protected MongoDatabase doGetDatabase() {
        MongoDatabaseFactory mongoDbFactory = MongoDbContext.getMongoDbFactory();
        return mongoDbFactory == null ? super.doGetDatabase() : mongoDbFactory.getMongoDatabase();
    }
}

八、封装mongo基础方法

public abstract class MongoDbDao<T> {

    /**
     * 反射获取泛型类型
     *
     * @return
     */
    protected abstract Class<T> getEntityClass();

    /**
     * 数据库模板
     */
    @Autowired
    protected MongoTemplate mongoTemplate;

    /***
     * 保存一个对象,若唯一性索引冲突,则直接覆盖
     * @param t
     */
    public T save(T t) {
        return this.mongoTemplate.save(t);
    }

    /**
     * 保存一个对象,若唯一性索引冲突,则新增失败
     *
     * @param t
     */
    public T insert(T t) {
        return this.mongoTemplate.insert(t);
    }

    /***
     * 保存对象列表
     *
     * @param batch
     */
    public Collection<T> batchInsert(Collection<T> batch) {
        return this.mongoTemplate.insert(batch, this.getEntityClass());
    }


    /***
     * 根据id从几何中查询对象
     * @param id
     * @return
     */
    public T getById(String id) {
        Query query = new Query(Criteria.where("_id").is(id));
        return this.mongoTemplate.findOne(query, this.getEntityClass());
    }

    /**
     * 根据自定义条件查询集合
     *
     * @param query
     * @return
     */
    public List<T> list(Query query) {
        return mongoTemplate.find(query, this.getEntityClass());
    }

    /**
     * 根据条件查询只返回一个文档
     *
     * @param query
     * @return
     */
    public T getOne(Query query) {
        return mongoTemplate.findOne(query.skip(0).limit(1), this.getEntityClass());
    }

    /***
     * 根据条件分页查询
     * @param query
     * @param start 查询起始值
     * @param size  查询大小
     * @return
     */
    public List<T> getPage(Query query, int start, int size) {
        return this.mongoTemplate.find(query.skip(start).limit(size), this.getEntityClass());
    }

    /***
     * 根据条件查询库中符合条件的记录数量
     * @param query
     * @return
     */
    public int count(Query query) {
        return (int) this.mongoTemplate.count(query, this.getEntityClass());
    }

    /**
     * 根据自定义条件删除集合
     *
     * @param query
     * @return
     */
    public int deleteBatch(Query query) {
        return (int) mongoTemplate.remove(query, this.getEntityClass()).getDeletedCount();
    }

    /**
     * 根据id删除
     *
     * @param id
     */
    public int deleteById(String id) {
        Query query = new Query(Criteria.where("_id").is(id));
        return (int) this.mongoTemplate.remove(query, this.getEntityClass()).getDeletedCount();
    }

    /**
     * 修改匹配到的第一条记录
     *
     * @param query
     * @param update
     */
    public UpdateResult updateFirst(Query query, Update update) {
        return this.mongoTemplate.updateFirst(query, update, this.getEntityClass());
    }

    /**
     * 修改匹配到的所有记录
     *
     * @param query
     * @param update
     */
    public UpdateResult updateMulti(Query query, Update update) {
        return this.mongoTemplate.updateMulti(query, update, this.getEntityClass());
    }

    /**
     * 聚合查询统计
     *
     * @param
     * @return
     */
    public <O> AggregationResults<O> aggregate(Aggregation aggregation, Class<O> outputType) {
        return mongoTemplate.aggregate(aggregation, this.getEntityClass(), outputType);
    }


    /**
     * 聚合查询统计
     *
     * @param
     * @return
     */
    public <O> AggregationResults<O> aggregate(TypedAggregation aggregation, Class<O> outputType) {
        return mongoTemplate.aggregate(aggregation, outputType);
    }
}

九、使用方式

  dao层继承MongoDbDao抽象类即可

@Repository
public class AlarmDataDao extends MongoDbDao<AlarmData> {

    @Override
    protected Class<AlarmData> getEntityClass() {
        return AlarmData.class;
    }

    @MongoSwitch("discover_center")
    public int countAnInt(Query query){
        return super.count(query);
    }
}

  

posted @ 2023-02-22 17:30  阳光、大地和诗歌  阅读(922)  评论(0编辑  收藏  举报