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

34
我正在使用Spring boot 2与Spring Data、Spring-Data-Elastisearch和Spring-data-Redis(用于HTTP会话)。 当我启动应用程序时,我收到了

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 应用程序仍会组件扫描层次结构,这就是我认为导致警告的原因。 - Darren Forsythe
我有同样的问题。我试图从任何地方排除所有内容,甚至从ComponentScan中排除。尝试明确指定每个仓库,现在每个实体都是javax.persistence.Entity,以避免混淆,但我仍然收到大约50条消息,Spring Data Redis不确定这个和那个仓库。我已经尝试了两个小时的所有方法,但无法使其正常工作。 - Dalibor Filus
2
你解决了这个问题吗?没有使用Redis的同样问题。 - chomp
我也遇到了与Spring Boot 2.0.2.RELEASE、spring-boot-starter-data-jpa:2.0.2.RELEASE和spring-data-elasticsearch:3.0.7.RELEASE相关的问题;EnableJpaRepositories和@EnableElasticsearchRepositories无法正常工作。 - davey
如何解决这个问题?我正在使用JPA和Spring-boot redis,但是数据保存在MySQL中而不是redis中,请帮助我。 - nitinsridar
7个回答

29
抱歉回复晚了,但我认为已有的答案并没有解释实际、深层次的原因为什么会发生这种情况。让我按顺序解释一切,以便让您了解细节(准备好了吗,它会相当冗长和全面)。如果您正在寻找简单的解决方案,请转到我的回答底部:
首先,Spring Data作为一个通用模块(忘记特定模块,如Spring Data JPA或Spring Data Redis),具有接口层次结构。它从Repository开始,然后是CrudRepository,之后是PagingAndSortingRepository。我不会详细介绍它们之间的区别,这不是现在的重点。重要的是-这些接口与特定的持久性存储完全隔离,只是因为它们技术上位于随任何特定Spring Data实现一起提供的单独JAR中(如果您感兴趣,可以查看官方文档)。
我的意思是-您可以使用Spring Data模块来处理MongoDB。为了利用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注解实际上是Spring Data注解,而不是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?或者是Cassandra?-无法以这种方式确定,请参见official doc。另一方面,当类路径中只有一个spring data模块时,spring可以自己推断出所有内容,因为它不会产生歧义。
您可以怎么做来解决它:
1. 扩展特定于技术的存储库。例如,如果您想要将实体A与PostgreSQL关联起来,则不要使用CrudRepository-使用JpaRepository。如果您想要将实体B与Redis关联起来,则使用RedisRepository等。
2. 使用指示其所属特定数据存储的注释对实体进行注释。@Entity、@Document、@Table等。
我希望现在这一点很清楚。我真的尽力向您解释了这个问题。感谢您的阅读,祝您有愉快的一天!

谢谢您的解释。您能否看一下这个问题:https://stackoverflow.com/questions/72669715/how-to-avoid-conflit-between-reactivecrudrepository-and-reactivemongorepository 我遇到了同样的警告,没有办法用类似JpaReactiveRepository的东西替换ReactiveCrudRepository。 - James
1
我认为作者并不是在问为什么他的存储库无法检测到关联的存储库。 - I have 10 fingers
1
实际上,他的代码库可以检测到其关联技术。问题在于 spring-data-redis 会产生意外的日志,它不知道哪些代码库不应该是 Redis 代码库,即使他已经指定了哪些类应该被视为其关联技术。 - I have 10 fingers
真是大开眼界啊!我使用了R2DBC和Reactive Mongo依赖,但我的Repository bean没有被扫描到。我深入研究了redis和r2dbc数据依赖共存的问题,这让我想起了基础知识!谢谢。 - Karthik R
关键点是对于所有的数据库仓库,使用extends JpaRepository而不是extends CrudRepository - raghavsood33

19

8

您的配置都正确。问题是由于 RedisRepositoriesAutoConfiguration 引起的。它只使用默认配置重复注册了 EnableRedisRepositories,其basePackages为空。

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

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

}

5
在其中一个项目中,我们有类似以下的信息:
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组件的操作方式类似。

0

这对我来说非常有效, 我正在使用两个数据源Mysql和MongoDb

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


0
在我的情况下,我正在使用Redis,因此将@RedisHash添加到实体类中以区分某些存储库。 输入图像描述

1
这只是帮助 spring-data-redis 检测哪个存储库应该是 RedisRepository,因此日志记录问题仍然存在。 - I have 10 fingers

0

也许现在已经太晚了,但无论如何。这只是一个信息性的消息,帮助您了解Spring Data模块的配置方式。 例如:

 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类,不会使用它。


1
如何解决这个问题?我正在使用JPA和Spring Boot,数据存储在MySQL而非Redis中,请帮忙。 - nitinsridar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接