Spring - 找到多个 Spring Data 模块,进入严格的存储库配置模式

新手上路,请多包涵

我正在使用带有 Spring Data、Spring-Data-Elastisearch 和 Spring-data-Redis(用于 http 会话)的 Spring boot 2。当我启动应用程序时。我正在接收

2017-10-29 17:38:33.376  INFO 18625 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2017-10-29 17:38:33.451  INFO 18625 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2017-10-29 17:38:33.461  INFO 18625 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2017-10-29 17:38:33.768  INFO 18625 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2017-10-29 17:38:33.783  INFO 18625 --- [  restartedMain] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.ecommerce.core.repository.elastic.ProductElasticSearchRepository.
2017-10-29 17:38:33.787  INFO 18625 --- [  restartedMain] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.ecommerce.core.repository.jpa.UserRepository.
2017-10-29 17:38:33.790  INFO 18625 --- [  restartedMain] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.ecommerce.core.repository.jpa.catalog.CategoryJsonWrapperRepository.
2017-10-29 17:38:33.793  INFO 18625 --- [  restartedMain] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.ecommerce.core.repository.jpa.catalog.CategoryRepository.
2017-10-29 17:38:33.794  INFO 18625 --- [  restartedMain] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.ecommerce.core.repository.jpa.catalog.ProductRepository.

在我的 App.java 文件中,我有以下几行(应该避免歧义)

 @EnableJpaRepositories(basePackages = {"com.ecommerce.core.repository.jpa"})
@EnableElasticsearchRepositories(basePackages= {"com.ecommerce.core.repository.elastic"})
@EnableRedisRepositories(basePackages = {"org.springframework.data.redis.connection.jedis"})

每个 spring 数据存储库都扩展了特定于他的工作接口(主要是 JpaRepository 和 ElasticsearchCrudRepository 之一

我读了这个 - https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.multiple-modules.types ,正如你所看到的,一切都应该没有问题。

原文由 ROZZ 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.3k
1 个回答

很抱歉回答得太晚了,但我认为目前的答案并不能解释 它发生 的实际、深刻的原因。让我解释一切,以便让您了解胆量(准备好,它将相当长而全面)。如果您正在寻找简单的解决方案,请转到我的答案的底部:

首先,spring data 作为一个通用模块(忘记特定模块,比如 spring data jpa 或 spring data redis),具有接口层次结构。它从 Repository 开始,然后是 CrudRepository,然后是 PagingAndSortingRepository。我不会详细介绍它们之间的区别,这不是重点。重要的是 - 这些接口与特定的持久性存储绝对隔离,只是因为它们在技术上驻留在单独的 JAR 中,该 JAR 会立即随任何特定的 spring 数据实现一起提供(它被称为 spring-data-commons ,请参阅 官方文档,如果你感兴趣)

我的意思是-您可以为 MongoDB 使用 Spring 数据模块。为了利用 spring data mongodb,您通常会做什么:对,扩展 CrudRepository,或 Repository 或 MongoRepository。这非常重要——从 spring-data 的角度来看,如果您通过扩展 Repository 或 CrudRepository 创建自己的接口 并且您没有标记目标存储库实体(我将在答案末尾解释),那么 Spring 基本上会尝试自己找出这个神奇的方法:findById、deleteById 等必须如何实现,因为显然它们的实现在 Mongo 和 JPA 中会有所不同。考虑到这一点,请继续阅读。

问题是 ——spring 究竟是如何 确定的,你必须实现自定义接口的方式?好吧,Spring 内部有一个抽象,称为 RepositoryFactoryBeanSupport 。这是实际参与从您的自定义存储库创建 bean 的东西。现在让我们做一个实验:尝试将 spring data jdbc starter 和 spring data mongodb starter 添加到您的项目中。您会注意到,在您的类路径中有 2 个不同的 RepositoryFactoryBeanSupport 实现

  1. JdbcRepositoryFactoryBean(来自spring data jdbc starter)
  2. MongoRepositoryFactoryBean(来自spring data mongo starter)

然后,假设我有一个实体,如下所示:

 @AllArgsConstructor
@NoArgsConstructor
@Data
public class Customer {

    @Id
    private Long id;

    @Column("firstname")
    private String firstName;

    @Column("phone")
    private String phone;
}

另请注意: Id 和 Column 注释实际上是弹簧数据注释, 而不是 JPA

然后让我们定义一个接口(简单的dao接口):

 public interface CustomerCRUDRepository extends CrudRepository<Customer, Long> {
    int countByFirstName(String firstName);
}

现在,在某处注入 CustomerCRUDRepository 类型的 bean。只需尝试引导应用程序 - 你会失败。为什么?让我们一起调查日志:

 RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!

RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode

RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.example.springdatajdbc.repositories.CustomerCRUDRepository

与您的问题相同的例外,不是吗?让我们最终打破这一点。现在让我最后回答这个问题。

那么,为什么会出现这个异常:

当您在项目中有多个 spring-data 模块时,尝试为特定实体创建一个接口,该接口 没有使用特定于持久性技术注释 的注释(如 javax.persistence 中的 @Entity 或 mongo 中的 @Document,您命名它),通过从 spring-data-commons 模块(即 Repository 或 CrudRepository)扩展接口 - 这根本不起作用,因为 spring 基本上不知道您的实体与哪个数据存储相关联。是 MongoDB 吗?还是JPA?还是卡桑德拉? - 不可能以这种方式确定,请参阅 官方文档。另一方面,当 classpath 中只有一个 spring 数据模块时,spring 可以自行得出结论,因为它没有歧义。

你能做些什么来解决它:

  1. 扩展 技术特定 的存储库。例如,如果您希望实体 A 与 PostgreSQL 相关联,则不要使用 CrudRepository - 使用 JpaRepository。如果您希望实体 B 与 Redis 关联,请使用 RedisRepository 等。

  2. 使用注释对您的实体进行注释,表明它与特定数据存储的关联。 @Entity、@Document、@Table 等等。

我希望,这现在很清楚了。我真的尽力向你解释了。感谢阅读,祝您有美好的一天!

原文由 misha2048 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进