Spring Data MongoDB 可以配置为支持每个存储库的不同数据库吗?

Can Spring Data MongoDB be configured to support a different database for each repository?

过去一周我一直在努力将 Spring 数据 MongoDB 成功集成到我们的应用程序中。我们使用相当普遍的做法,为我们依赖的每个集合使用单独的数据库。例如,TenantConfiguration 数据库仅包含 TenantConfigurations 集合。

我已多次阅读文档并浏览代码以寻找解决方案,但一无所获。这样一个广泛采用的项目肯定可以解决这个问题吗?我目前的尝试是这样的:

@Configuration
@EnableMongoRepositories(basePackages = "com.whatever.service.repository",
        basePackageClasses = TenantConfigurationRepository.class,
        mongoTemplateRef = "tenantConfigurationTemplate")
public class TenantConfigurationRepositoryConfig {

    @Value("${mongo.hosts}")
    private List<String> mongoHosts;

    @Bean
    public MongoTemplate tenantConfigurationTemplate() throws Exception {
        final List<ServerAddress> serverAddresses = new ArrayList<>();
        for (String host : mongoHosts) {
            serverAddresses.add(new ServerAddress(host, 27017));
        }

        final MongoClientOptions clientOptions = new MongoClientOptions.Builder()
                .connectTimeout(25000)
                .readPreference(ReadPreference.primaryPreferred())
                .build();

        final MongoClient client = new MongoClient(serverAddresses, clientOptions);
        return new MongoTemplate(client, "TenantConfiguration");
    }
}

这是其他单个存储库配置之一:

@Configuration
@EnableMongoRepositories(basePackages = "com.whatever.service.repository",
        basePackageClasses = RegisteredCardRepository.class,
        mongoTemplateRef = "registeredCardTemplate")
public class RegisteredCardRepositoryConfig {

    @Value("${mongo.hosts}")
    private List<String> mongoHosts;

    @Bean
    public MongoTemplate registeredCardTemplate() throws Exception {
        final List<ServerAddress> serverAddresses = new ArrayList<>();
        for (String host : mongoHosts) {
            serverAddresses.add(new ServerAddress(host, 27017));
        }

        final MongoClientOptions clientOptions = new MongoClientOptions.Builder()
                .connectTimeout(25000)
                .readPreference(ReadPreference.primaryPreferred())
                .build();

        final MongoClient client = new MongoClient(serverAddresses, clientOptions);
        return new MongoTemplate(client, "RegisteredCard");
    }
}

现在这是 RegisteredCard 存储库的实际存储库定义:

@Repository
public interface RegisteredCardRepository extends MongoRepository<RegisteredCard, Guid>,
        QueryDslPredicateExecutor<RegisteredCard> { }

这一切对我来说都很有意义,各个配置唯一地标识了它们配置的 specific 存储库接口和 specific 模板 bean通过注释的 mongoTemplateRef 参数与该存储库一起使用。至少,这就是文档似乎暗示它应该起作用的方式。

实际上,当我启动应用程序时,RegisteredCard 存储库解析为一个 MongoDB 存储库实例,该实例具有绑定到 TenantConfiguration 数据库的关联 MongoDbFactory。事实上,每个存储库都会收到相同的、不正确的 MongoOperations 对象。尽管每个存储库都有自己独特的配置,但似乎首先访问的数据库仍然是 every 存储库的目标数据库。

这个问题有什么解决办法吗?

我花了将近一周的时间,但实际上我找到了解决这个问题的可行方法。这是我在研究这个问题时收集到的事实的快速 运行 总结:

  • @EnableMongoRepositories(basePackageClasses = Whatever.class) 只是使用限定的 class 名称来指示它应该扫描哪些 package all您定义的数据模型。如果 Whatever.class 驻留在那个包中,这完全等同于执行 @EnableMongoRepositories(basePackageClasses = "com.mypackage.whatevers")
  • @EnableMongoRepositories 不可重复,但可用于注释多个 class。这已在其他 SO 对话中进行了介绍,但值得在此重复。您将需要定义 几个 存储库配置 classes; 一个用于您打算与之交互的每个数据库
  • 您的每个单独的存储库配置都必须在 @EnableMongoRepositories 注释中指定其自己的 MongoTemplate 实例。您可以只提供一个 Mongo bean,但 MongoTemplate 依赖于特定的 MongoMappingContext
  • @EnableMongoRepositories 注释有助于定义您的映射上下文,它了解您的数据模型的结构以及如何序列化它们。它还理解 @Document@Field 注释并执行持久化对象的繁重工作。 Mongo 模板实例是您指定要与之交互的数据库的地方。因此,通过为 @EnableMongoRepositories 注释提供 basePackage 属性和 mongoTemplateRef 属性,您可以将 Spring 数据 Mongo 告诉 "take these models and persist them in this specific database"。

此解决方案的不幸要求是您必须根据它们所属的数据库将数据模型组织到单独的包中。如果像我一样,您使用的是 Mongo 数据库结构,该结构分配了一个集合到每个数据库(这对于访问频繁的集合来说很常见),这意味着您的每个数据模型都必须驻留在自己的包中。这些包中的每一个都必须由 @EnableMongoRepositories 注释指向,该注释还包含指向唯一 MongoTemplate bean 的 mongoTemplateRef 属性。

我希望这可以帮助别人避免我在尝试完成应该是 运行-of-the-mill Mongo 集成时遇到的麻烦。

PS: 放弃所有希望,那些寻求将审计与此配置相结合的人。

我知道这已经过时了,但对于像我这样正在寻找简短解决方案的人来说:

@Autowired
@Qualifier("registeredCardTemplate")
private MongoTemplate template;

限定符名称是您的“mongoTemplateRef={XXX}”