目录
1、前言
2、mongodb多数据源配置
2.1 maven依赖
2.2 mongodb配置
2.3 创建mongodb属性类和配置类
3、设置数据源的路由key 以及 查找数据源
3.1 定义数据源枚举
3.2 模板DynamicMongoTemplater
4、切面
4.1 定义切面注解
4.2 切面实现类
5 测试controller
今天讲讲mongodb多数据源配置,思路和上一篇springboot+mybatis多数据源配置差不多,jdk版本还是1.8,springboot版本还是1.5.21。
org.springframework.boot
spring-boot-starter-aop
org.aspectj
aspectjweaver
commons-lang
commons-lang
2.6
org.springframework.boot
spring-boot-starter-data-mongodb
##mongodb数据源, 用户名密码、鉴权这些省略,此处演示不配置
mongodb:
databases:
mongodb_1: ##这是我自定义的dbname
name: mongodb_1
uri: mongodb://192.168.1.15:27017/mongodb_1
mongodb_2:
name: mongodb_2
uri: mongodb://192.168.1.15:27017/mongodb_2
import com.alibaba.fastjson.JSONObject;
/**
* mongodb属性
* @author LongBJ
*
*/
public class MongodbProperties {
private String name;
private String uri;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}
这里的name,uri和配置文件的属性对应,不然后面无法注入。mongodb配置类
/**
** mongodb配置类
**/
@Configuration
@ConfigurationProperties(prefix = "mongodb")
@PropertySource("classpath:bootstrap.yml")
public class MongodbConfig {
// databases也要和配置文件属性名对应
private Map databases = new HashMap<>();
public Map getDatabases() {
return databases;
}
public void setDatabases(Map databases) {
this.databases = databases;
}
}
public enum DataSourceEnum {
DS_MONGODB_1("mongodb_1", "mongodb_1数据源"),
DS_MONGODB_2("mongodb_2", "mongodb_2数据源");
private String value;
private String display;
DataSourceEnum(String value, String display) {
this.value = value;
this.display = display;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
}
接下来,我们利用ThreadLocal将数据源设置到每个请求的线程上下文当中,代码如下:
port java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
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.SimpleMongoDbFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.mongodb.MongoClientURI;
@Component
public class MongodbContextHolder {
// 数据源对应的MongoDbFactory Map
private static final Map MONGO_CLIENT_DB_FACTORY_MAP = new HashMap<>();
// 当前线程ThreadLocal绑定的数据源工厂
private static final ThreadLocal MONGO_DB_FACTORY_THREAD_LOCAL = new ThreadLocal<>();
@Autowired
private MongodbConfig mongodbConfig;
@PostConstruct
public void afterPropertiesSet() throws UnknownHostException {
Map databases = mongodbConfig.getDatabases();
if (!CollectionUtils.isEmpty(databases)) {
for(Entry entry : databases.entrySet()) {
MongodbContextHolder.MONGO_CLIENT_DB_FACTORY_MAP.put(entry.getKey(),
new SimpleMongoDbFactory(new MongoClientURI(entry.getValue().getUri())));
}
}
}
@Bean(name = "dynamicMongoTemplate")
public DynamicMongoTemplate dynamicMongoTemplate() {
Iterator iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator();
return new DynamicMongoTemplate(iterator.next());
}
@Bean(name = "mongoDbFactory")
public MongoDbFactory mongoDbFactory() {
Iterator 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();
}
}
动态获取mongodb数据源的模板如下:
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.DB;
/**
* mongodb数据源动态模板
* @author LongBJ
*
*/
public class DynamicMongoTemplate extends MongoTemplate {
public DynamicMongoTemplate(MongoDbFactory mongoDbFactory) {
super(mongoDbFactory);
}
/**
* springboot 1.x版本
* 重写getDb
*/
@Override
public DB getDb() {
MongoDbFactory mongoDbFactory = MongodbContextHolder.getMongoDbFactory();
return mongoDbFactory.getDb();
}
/**
* springboot2.x 版本
@Override
protected MongoDatabase doGetDatabase() {
MongoDbFactory mongoDbFactory = MongodbContextHolder.getMongoDbFactory();
return mongoDbFactory == null ? super.doGetDatabase() : mongoDbFactory.getDb();
}*/
}
@Documented
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface MongodbDynamicDS {
DataSourceEnum value() default DataSourceEnum.DS_KUAIMA_MEDICAL;
}
有了切面注解,还需要实现切面拦截,实现非常简单,只需要定义一个类,在类上使用@Aspect和@Component即可实现。
import java.util.Objects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.kingseok.hospital.common.annotation.MongodbDynamicDS;
import com.kingseok.hospital.common.configuration.DataSourceEnum;
import com.kingseok.hospital.common.mongodb.MongodbContextHolder;
/**
* mongodb数据源切面
* @author LongBJ
*
*/
@Aspect
@Component
public class MongodbAspect {
private final static Logger _logger = LoggerFactory.getLogger(DynamicDatasourceAspect.class);
@Pointcut("@within(com.kingseok.hospital.common.annotation.MongodbDynamicDS)")
public void mongodbDSourcePointCut() {}
@Pointcut("@annotation(com.kingseok.hospital.common.annotation.MongodbDynamicDS)")
public void mongodbDSourcePointCut2() {}
@Around("mongodbDSourcePointCut() || mongodbDSourcePointCut2()")
public Object getMongodbDynamicDS(ProceedingJoinPoint joinPoint) throws Throwable {
DataSourceEnum ds = getDSAnnocation(joinPoint).value();
_logger.info("MongodbAspect : getMongodbDynamicDS -> ds_key={}", ds.getValue());
MongodbContextHolder.setMongoDbFactory(ds.getValue());
try{
return joinPoint.proceed();
}finally {
MongodbContextHolder.removeMongoDbFactory();
_logger.info("MongodbAspect : getMongodbDynamicDS -> ThreadLocal已删除ds_key={}", ds.getValue());
}
}
private MongodbDynamicDS getDSAnnocation(ProceedingJoinPoint joinPoint) {
Class> targetClazz = joinPoint.getTarget().getClass();
MongodbDynamicDS ds = targetClazz.getAnnotation(MongodbDynamicDS.class);
// 先判断类的注解,再判断方法注解
if(Objects.nonNull(ds)) {
return ds;
}
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
return methodSignature.getMethod().getAnnotation(MongodbDynamicDS.class);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@MongodbDynamicDS(value = DataSourceEnum.DS_MONGODB_1)
public class DatasourceDemoApplicationTests {
@Autowired
private MongoTemplate dynamicMongoTemplate;
@Override
public JSONObject getPddImById(String id) {
String collectionName = "bizrecord"; // 表名
QueryBuilder queryBuilder = new QueryBuilder();
queryBuilder.and(new BasicDBObject("_id", id));
Query query = new BasicQuery(queryBuilder.get());
JSONObject record = dynamicMongoTemplate.findOne(query, JSONObject.class, collectionName);
return record ;
}
@Test
@MongodbDynamicDS(value = DataSourceEnum.DS_MONGODB_1) // 作用于方法上
public JSONObject test() {
String collectionName = "bizrecord"; // 表名
QueryBuilder queryBuilder = new QueryBuilder();
queryBuilder.and(new BasicDBObject("_id", id));
Query query = new BasicQuery(queryBuilder.get());
JSONObject record = dynamicMongoTemplate.findOne(query, JSONObject.class, collectionName);
return record ;
}
}