基础的东西不谈,先说思路。
我们跟踪源码可以发现每次查询时都会在MongoTemplate
中去获取MongoDatabase
实例,大概是这样:
FindIterable<Document> iterable = collectionCallback
.doInCollection(getAndPrepareCollection(getDb(), collectionName));
其中getDb()是由工厂类MongoDbFactory
实现的。那么很简单了,我们只需要写一个自己的MongoDbFactory
配置进来,来实现“默认是当前月库,也可以手动选择月库”的效果。
上代码,首先是MongoDbFactory
:
/**
* 继承 {@link SimpleMongoDbFactory },重写{@code getDB}方法,添加月库实现
*
* @author fonlin
* @date 2018/6/28
*/
public class MonthlyMongoDbFactory extends SimpleMongoDbFactory {
/**
* 没有月库后缀的数据库名
*/
private String databaseName;
public MonthlyMongoDbFactory(MongoClientURI uri) {
super(uri);
}
public MonthlyMongoDbFactory(MongoClient mongoClient, String databaseName) {
super(mongoClient, databaseName);
this.databaseName = databaseName;
}
public MongoDatabase getDb() throws DataAccessException {
//获取当前ThreadLocal中的month
String month = MonthSelector.getAndRemove();
//如果没有,则设置当前月
if (StringUtils.isEmpty(month)) {
month = LocalDateTime.now().format(DateTimeFormatter.ofPattern(Constants.MONTH_PATTERN));
}
return getDbByMonth(month);
}
private MongoDatabase getDbByMonth(String month) throws DataAccessException {
Assert.hasText(month, "month must not be empty.");
//拼出test_201806
String name = this.databaseName + "_" + month;
//调用父类
return super.getDb(name);
}
}
很简单,继承默认实现SimpleMongoDbFactory
,重写getDb()方法加入我们自己的逻辑,最终还是调用父类的getDb(String dbName)方法。注意MonthSelector
,这是利用ThreadLocal
实现的手动选择月份策略,用法大概就是这样子:
MonthSelector.set("201805");
List<User> users = userDao.findAll();
这里把MonthSelector
粗略代码贴一下,不太懂的朋友们要去看下ThreadLocal
的原理。
/**
* @author fonlin
* @date 2018/6/28
*/
public class MonthSelector {
private static final ThreadLocal<String> LOCAL_MONTH = new ThreadLocal<>();
public static String getAndRemove() {
String month = LOCAL_MONTH.get();
LOCAL_MONTH.remove();
return month;
}
public static void set(String month) {
Assert.notNull(month, "month must not be null");
LOCAL_MONTH.set(month);
}
public static String get() {
return LOCAL_MONTH.get();
}
}
最后是springboot整合mongodb的java config:
@Configuration
//必须要禁用spring boot的自动配置
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@EnableConfigurationProperties(MongoProperties.class)
//激活@Repository注解,并且设置dao扫描包
@EnableMongoRepositories(basePackages = "com.fonlin.cloudmanager.dao.mongodb")
public class MongoDbConfig extends AbstractMongoConfiguration {
private final MongoProperties properties;
private final MongoClientFactory factory;
private final MongoClientOptions options;
private MongoClient mongo;
public MongoDbConfig(MongoProperties properties,
ObjectProvider<MongoClientOptions> options, Environment environment) {
this.properties = properties;
this.options = options.getIfAvailable();
this.factory = new MongoClientFactory(properties, environment);
}
@Bean
public MongoDbFactory mongoDbFactory() {
//这里new我们自己的MongoDbFactory即可
return new MonthlyMongoDbFactory(mongoClient(), getDatabaseName());
}
@PreDestroy
public void close() {
if (this.mongo != null) {
this.mongo.close();
}
}
@Override
public MongoClient mongoClient() {
this.mongo = this.factory.createMongoClient(this.options);
return this.mongo;
}
@Override
protected String getDatabaseName() {
return this.properties.getDatabase();
}
}
到此配置就结束了,使用的话就像jpa
Repository
一样使用即可。