日志平台要连接多个mongo库做日志统一查询,使用springboot的多Template模式不能做到动态切换,所以这里做一个动态模板实现自动切换。
DynamicMongoTemplate继承 MongoTemplate重写doGetDatabase方法,这个方法是protected修饰的,一看就知道是提供给咱们重写的。
import com.mongodb.client.MongoDatabase;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
* @author DAI
* @date 2020/5/30 12:51
* @Description 动态mongo模板
*/
public class DynamicMongoTemplate extends MongoTemplate {
public DynamicMongoTemplate(MongoDbFactory mongoDbFactory) {
super(mongoDbFactory);
}
@Override
protected MongoDatabase doGetDatabase() {
MongoDbFactory mongoDbFactory = MongoContext.getMongoDbFactory();
return mongoDbFactory == null ? super.doGetDatabase() : mongoDbFactory.getDb();
}
}
注册DynamicMongoTemplate替换springboot自动配置的MongoTemplate
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author DAI
* @date 2020/5/30 13:55
* @Description TODO
*/
@Component
public class MongoContext {
private static final Map<String, MongoDbFactory> MONGO_CLIENT_DB_FACTORY_MAP = new HashMap<>();
private static final ThreadLocal<MongoDbFactory> MONGO_DB_FACTORY_THREAD_LOCAL = new ThreadLocal<>();
@Autowired
MongoListProperties mongoListProperties;
@PostConstruct
public void afterPropertiesSet() {
if (!CollectionUtils.isEmpty(mongoListProperties.getList())) {
mongoListProperties.getList().forEach(info->{
MONGO_CLIENT_DB_FACTORY_MAP.put(info.getDatabase(), new SimpleMongoClientDbFactory(info.getUri()));
});
}
}
@Bean(name = "mongoTemplate")
public DynamicMongoTemplate dynamicMongoTemplate() {
Iterator<MongoDbFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
return new DynamicMongoTemplate(iterator.next());
}
@Bean(name = "mongoDbFactory")
public MongoDbFactory mongoDbFactory() {
Iterator<MongoDbFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
return iterator.next();
}
public static void setMongoDbFactory(String name) {
MONGO_DB_FACTORY_THREAD_LOCAL.set(MONGO_CLIENT_DB_FACTORY_MAP.get(name));
}
public static MongoDbFactory getMongoDbFactory() {
return MONGO_DB_FACTORY_THREAD_LOCAL.get();
}
public static void removeMongoDbFactory(){
MONGO_DB_FACTORY_THREAD_LOCAL.remove();
}
}
mongo的配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @author DAI
* @date 2020/5/30 20:05
* @Description TODO
*/
@Data
@ConfigurationProperties(prefix = "message.mongo")
public class MongoListProperties {
private List<MongoList> list;
@Data
public static class MongoList {
private String uri;
private String database;
}
}
配置信息

自定义数据源切换注解
/**
* 数据源切换
* @author daiwenlong
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MongoSwitch {
String value() default "";
} 自动切换切面
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author DAI
* @date 2020/5/30 18:43
* @Description 数据源切换切面
*/
@Slf4j
@Aspect
@Component
public class MongoAspect {
@Pointcut("@annotation(com.dwl.message.monitor.annotation.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);
MongoContext.setMongoDbFactory(mongoSwitch.value());
} catch (Exception e) {
log.error("==========>前置数据源切换异常", e);
}
}
@After("mongoSwitch()")
public void after(JoinPoint point) {
try {
MongoContext.removeMongoDbFactory();
} catch (Exception e) {
log.error("==========>后置数据源切换异常", e);
}
}
}
关于使用的问题,可以直接在方法上使用@MongoAspect("dbName")注解,dbName为你要切换的数据库名称。
也可以使用在代码里直接使用MongoContext.setMongoDbFactory(dto.getDataBase())进行数据源切换
pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>