【问题标题】:Spring Boot detects 2 identical repository beansSpring Boot 检测到 2 个相同的存储库 bean
【发布时间】:2017-04-28 15:18:22
【问题描述】:

我正在使用带有 Spring Data JPA 的 Spring Boot,只有一个 @SpringBootApplication。而且我还有一个存储库类,例如:

package com.so;
public interface SORepository {
    //methods
}

然后实现

@Repository("qualifier")
@Transactional(readOnly = true)
public class SORepositoryImpl implements SORepository {
   //methods
}

问题是,当我启动应用程序时,出现以下错误:

Parameter 0 of constructor in com.so.SomeComponent required a single bean, but 2 were found:
    - qualifier: defined in file [path\to\SORepositoryImpl.class]
    - soRepositoryImpl: defined in file [path\to\SORepositoryImpl.class]

所以,如您所见,一个存储库类的 2 个 bean 以某种方式被创建了。我该如何解决这个问题?

【问题讨论】:

  • 您的 SORepository 是否扩展了 Spring Data Repository(或类型层次结构中的某些内容)?
  • 不,这就是我在这里提供它的原因。 SORepository 只是一个简单的接口。
  • 你在某个地方定义了 bean SORepositoryImpl 吗?也许像这样的java配置 @Bean public SORepositoryImpl sORepositoryImpl() { return new SORepositoryImpl(); }
  • 你的@Configuration 类呢?可能您正在那里创建一个实例(ID 为“soRepositoryImpl”的实例)。
  • 我认为@Slavus 可能是对的:我发现重现此问题的唯一方法是显式定义一个名称为(bean 创建方法)soRepositoryImpl 的 bean,但也通过 a 引用此 bean不匹配的名称(例如@Bean public String foo(SORepository soRepository))没有匹配项,也没有最好的spring猜测。

标签: spring spring-boot spring-data spring-data-jpa


【解决方案1】:

您可以使用已创建代理元素的 Spring Data JPA 方法,然后将其注入公共类 SORepositoryImpl:

public interface Proxy() extends JpaRepository<Element, Long>{
     Element saveElement (Element element); //ore other methods if you want}

比:

@Repository
@Transactional(readOnly = true)
public class SORepositoryImpl implements SORepository {

@Autowired
private Proxy proxy;

   //end realisation of methods from interface SORepository 
}

【讨论】:

    【解决方案2】:

    尝试从 SORepositoryImpl 类中去掉 @Repository 注释

    例如

    @Transactional(readOnly = true)
    public class SORepositoryImpl implements SORepository {
       //methods
    }
    

    错误消息暗示您有两个 bean,一个名为“qualifier”,一个名为“soRepositoryImpl”,它可能在 Config 类中。

    【讨论】:

      【解决方案3】:

      假设你没有额外的配置类/xml,我想你应该分享你的 SomeComponent 类。我的看法是,您在定义为“限定符”的地方注入了“soRepositoryImpl”。他们有两个选择。我想说只删除注释参数“限定符”,它应该可以工作。

      此外,除非您确实要指定自定义 DAO 实现,否则您可以完全避免使用 @Repository(这是您用来使其可注入您的服务的注释)。您可以创建一个扩展 Spring 接口的接口并定义查询方法。

      例如:

      public interface PersonRepository extends Repository<User, Long> {
      
        List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); 
      

      然后你可以直接将它注入你的服务/控制器。

        private final PersonRepository personRepository;
        public PersonController(final PersonRepository personRepository) {
          this.personRepository = personRepository;
        }
      

      检查样本: https://spring.io/guides/gs/accessing-data-jpa/

      http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html

      【讨论】:

      • SomeComponent 中没有额外的逻辑,只是自动装配 SORepository 没有任何限定符。
      • 当然我知道扩展spring接口,但在这种特殊情况下,我不想扩展jpa接口,而是使用我自己的实现。
      • 所以没有删除限定符?您还有其他 bean 配置设置吗?
      【解决方案4】:

      好的,我找到了问题所在。

      我只是不明白,Spring 如何创建第二个 bean (soRepositoryImpl),因为我从来没有告诉过它,无论是明确地还是在配置类中。但我发现我们在我的另一个 SORepository 的实例化过程中创建的第二个 bean(它位于不同的包 com.another 并扩展了 JpaRepository)。

      因此,当 Spring 尝试解决 com.another.SORepository 的所有依赖项时,它以某种方式找到了我的 com.so.SORepositoryImpl(它与 com.another.SORepository 完全不同——不是扩展\实现,不是 jpa 的东西,只有相似的名称!)。

      对我来说这似乎是一个 Spring 错误,因为它不检查存储库依赖类的真实继承,只有 name + Impl(即使在不同的包中)适合他。

      我唯一应该做的就是重命名 `com.so.SORepositoryImpl 并且它不再是 2 个 bean。

      谢谢大家的回答!

      【讨论】:

        猜你喜欢
        • 2021-06-09
        • 2020-01-07
        • 1970-01-01
        • 2018-03-30
        • 2018-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-07
        相关资源
        最近更新 更多