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); } }