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

Posted

技术标签:

【中文标题】Spring - 找到多个 Spring Data 模块,进入严格的存储库配置模式【英文标题】:Spring - Multiple Spring Data modules found, entering strict repository configuration mode 【发布时间】:2018-04-10 15:44:47 【问题描述】:

我正在使用带有 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,正如你所见,一切都应该没有问题。

【问题讨论】:

Spring Boot 应用程序仍将组件扫描层次结构,我认为这是导致警告的原因。 我也有同样的问题。我试图从任何地方排除一切,甚至从 ComponentScan 中排除。试图明确指定所有内容,每个存储库现在都是 JpaRepository 以避免混淆,每个实体都是 javax.persistence.Entity,但我仍然收到大约 50 条消息,表明 Spring Data Redis 不确定这个和那个存储库。我现在尝试了两个小时,但无法正常工作。 您解决了这个问题吗?没有redis也一样。 我对 spring boot 2.0.2.RELEASE、spring-boot-starter-data-jpa:2.0.2.RELEASE 和 spring-data-elasticsearch:3.0.7.RELEASE 有同样的问题; EnableJpaRepositories 和 @EnableElasticsearchRepositories 不起作用 解决这个问题的方法是什么?我正在研究 JPA 和 Spring-boot redis,数据保存在 mysql 中而不是 redis 中,请帮助 【参考方案1】:

可能为时已晚,但无论如何。这只是一条信息性消息,可帮助您了解 Spring Data Modules 的配置方式。 例如:

 INFO 87518 --- [main] .RepositoryConfigurationExtensionSupport : 
     Spring Data JPA - Could not safely identify store assignment for repository 
          candidate interface com.some.package.MyRepository.

意味着 Spring Data JPA 模块将跳过 MyRepository 类并且不会使用它。

【讨论】:

解决这个问题的方法是什么?我正在研究 JPA 和 Spring-boot redis,数据保存在 MySql 中而不是 redis 中,请帮助【参考方案2】:

你的配置没问题。问题是由RedisRepositoriesAutoConfiguration 引起的。它仅使用默认配置重复注册EnableRedisRepositories,其中basePackages为空。

要解决此问题,您可以通过以下方式排除RedisRepositoriesAutoConfiguration

@SpringBootApplication(
        exclude =  RedisRepositoriesAutoConfiguration.class 
)
public class MySpringBootApp 


【讨论】:

【参考方案3】:

在其中一个项目中,我们收到了如下消息:

Spring Data LDAP - Could not safely identify store assignment for repository candidate interface com.company.xxx.EncryptionKeyRepository.

解决方案是将此行添加到 application.properties 文件中

spring.data.ldap.repositories.enabled=false

这适用于 Spring Data LDAP。我想其他 Spring Data 组件也是类似的。

【讨论】:

【参考方案4】:

由于您明确启用特定软件包的存储库。您可以将其包含在 application.properties 中以避免这些错误:

spring.data.redis.repositories.enabled=false

您也可以对其他存储库执行相同的操作。如果遇到类似错误:

spring.data.elasticsearch.repositories.enabled=false
spring.data.jpa.repositories.enabled=false

参考: https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html

【讨论】:

【参考方案5】:

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

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

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

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

    JdbcRepositoryFactoryBean(来自spring data jdbc starter) 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 注释实际上是 spring 数据注释,不是 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 , 或者 @Document 在 mongo 的情况下, 你命名它), 通过从 spring-data-commons 模块(即 Repository 或 CrudRepository) 扩展接口 - 这根本不起作用, 因为 spring 基本上不知道数据到底是哪个存储您的实体关联。是 MongoDB 吗?还是JPA?还是卡桑德拉? - 无法以这种方式确定,请参阅official doc。另一方面,当 classpath 中只有一个 spring 数据模块时,spring 可以自行得出结论,因为它没有歧义。

你能做些什么来解决它:

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

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

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

【讨论】:

【参考方案6】:

这对我来说就像一个魅力, 我正在使用两个数据源 Mysql 和 MongoDb

@EnableJpaRepositories(basePackages = "com.repository.MysqlRepository") @EnableMongoRepositories(basePackages = "com.repository.MongoRepository")

【讨论】:

以上是关于Spring - 找到多个 Spring Data 模块,进入严格的存储库配置模式的主要内容,如果未能解决你的问题,请参考以下文章

如何找到正确的 Spring Data JPA 和 Spring 版本的 jar 文件

在哪里可以找到 spring-data-elasticsearch 配置属性的参考?

spring-data-elasticsearch 在多个索引中搜索特定字段

Spring Data Elasticsearch:具有相同文档的多个索引

spring-data-mongodb 在一个 Mongo 实例中连接多个数据库

带有 Spring Boot 的 Spring Data JPA 中的多个数据源,[重复]