springboot mongodb 切换数据库
spring boot + mongodb 切换数据库,注意这里是切换数据库而非多数据源。适用场景是在业务场景中根据参数切换 mongo 数据库名。
版本 :
- springboot 2.3.4
- mongodb-driver 4.0.5
maven 依赖 :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
yml 配置 :
mongo:
datasource:
lists:
- uri: mongodb://ip:port/databaseName1
database: databaseName1
- uri: mongodb://ip:port/databaseName2
database: databaseName2
定义 mongo 属性类:
@Data
@Component
@ConfigurationProperties(prefix = "mongo.datasource")
public class MongoProperties {
private List<MongoList> lists;
@Data
public static class MongoList {
private String uri;
private String database;
}
}
重写 MongoTemplete 类 :
public class DynamicMongoTemplate extends MongoTemplate {
public DynamicMongoTemplate(MongoDatabaseFactory mongoDbFactory, MongoConverter mongoConverter) {
super(mongoDbFactory, mongoConverter);
}
@Override
protected MongoDatabase doGetDatabase() {
MongoDatabaseFactory factory = MongoContext.getMongoDatabaseFactory();
return factory == null ? super.doGetDatabase() : factory.getMongoDatabase();
}
}
定义 mongo context :
@Component
public class MongoContext {
private static final Logger logger = LogManager.getLogger(MongoContext.class);
private static final Map<String, MongoDatabaseFactory> databaseFactoryMap = new HashMap<>();
private static final ThreadLocal<MongoDatabaseFactory> databaseThreadLocal = new ThreadLocal<>();
private final MongoProperties mongoProperties;
public MongoContext(MongoProperties mongoProperties) {
this.mongoProperties = mongoProperties;
}
@PostConstruct
public void afterPropertiesSet() {
List<MongoProperties.MongoList> list = mongoProperties.getLists();
MongoProperties.MongoList properties = new MongoProperties.MongoList();
// 注: 此处 add 一个 mongo database 只是为了解决下面的 mongoTemplate() 方法
// 中 iterator.hasNext() 为 false 时启动报错的问题,实际上 test database 并不存在
properties.setDatabase("test");
properties.setUri("mongodb://pi:port/test");
if (!CollectionUtils.isEmpty(list)) {
list.add(properties);
list.forEach(mongo -> {
databaseFactoryMap.put(mongo.getDatabase(),
new SimpleMongoClientDatabaseFactory(mongo.getUri()));
});
}
}
@Bean(name = "mongoTemplate") // 此处 name 的定义需与具体 MongoTemplete 的注入处保持一致
public DynamicMongoTemplate mongoTemplate() {
Iterator<MongoDatabaseFactory> iterator = databaseFactoryMap.values().iterator();
DbRefResolver refResolver = new DefaultDbRefResolver(iterator.next());
MongoMappingContext mappingContext = new MongoMappingContext();
// 设置驼峰命名转换
mappingContext.setFieldNamingStrategy(new SnakeCaseFieldNamingStrategy());
return new DynamicMongoTemplate(iterator.next(),
new MappingMongoConverter(refResolver, mappingContext));
}
@Bean(name = "mongoDatabaseFactory")
public MongoDatabaseFactory mongoDatabaseFactory() {
Iterator<MongoDatabaseFactory> iterator = databaseFactoryMap.values().iterator();
return iterator.next();
}
public static void setMongoDatabaseFactory(String databaseName) {
logger.info("当前使用 mongo databaseName " + databaseName);
databaseThreadLocal.set(databaseFactoryMap.get(databaseName));
}
public static MongoDatabaseFactory getMongoDatabaseFactory() {
return databaseThreadLocal.get();
}
public static void removerMongoDatabaseFactory() {
databaseThreadLocal.remove();
}
}
使用示例 :
@Service
public class TestServiceImpl implements TestService {
private final DynamicMongoTemplete mongoTemplete;
// 以构造方法的方式注入
public TestServiceImpl(DynamicMongoTemplete mongoTemplete) {
this.mongoTemplete = mongoTemplete;
}
@Override
public void test(String databaseName, String collectionName) {
// 根据参数切换 database
MongoContext.setMongoDatabaseFactory(databaseName);
// 查询
mongoTemplete.findAll(TestPo.class, collectionName);
}
}
@XGLLHZ-《千千阙歌》.mp3-陈慧娴