spring data mongodb配置+月库实现

基础的东西不谈,先说思路。

我们跟踪源码可以发现每次查询时都会在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一样使用即可。

猜你喜欢

转载自blog.csdn.net/opiqi/article/details/80905175
今日推荐