springboot+mongodb多数据源配置

目录

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


1、前言

今天讲讲mongodb多数据源配置,思路和上一篇springboot+mybatis多数据源配置差不多,jdk版本还是1.8,springboot版本还是1.5.21。

2、mongodb多数据源配置

2.1 maven依赖

      
  
	    org.springframework.boot
	    spring-boot-starter-aop
	
	
	
		org.aspectj
		aspectjweaver
	
	
	
        commons-lang
        commons-lang
        2.6
    
	
	
		org.springframework.boot
		spring-boot-starter-data-mongodb
	

2.2 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

2.3 创建mongodb属性类和配置类

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

3、设置数据源的路由key 以及 查找数据源

3.1 定义数据源枚举

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

3.2 模板DynamicMongoTemplater

        动态获取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();
    }*/
}

4、切面

4.1 定义切面注解

@Documented
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface MongodbDynamicDS {

	DataSourceEnum value() default DataSourceEnum.DS_KUAIMA_MEDICAL;
}

4.2 切面实现类

        有了切面注解,还需要实现切面拦截,实现非常简单,只需要定义一个类,在类上使用@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);
	}
	
}

5 测试controller

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

你可能感兴趣的:(mongodb,spring,boot,数据库)