spring 使用独特的 bean 自动装配:Spring 预计单个匹配 bean,但发现 2

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8414287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:47:41  来源:igfitidea点击:

spring autowiring with unique beans: Spring expected single matching bean but found 2

springspring-mvcdependency-injectionannotationsautowired

提问by Rob McFeely

I am trying to autowire some beans (for dependency injection) using Spring for a webapp. One controller bean contains another bean which in turn holds a hashmap of another set of beans. For now the map only has one entry. When i run in tomcat and call the service I get an error saying that the second bean (held in the controller) is not unique

我正在尝试使用 Spring 为 webapp 自动装配一些 bean(用于依赖注入)。一个控制器 bean 包含另一个 bean,该 bean 又包含另一组 bean 的哈希图。目前地图只有一个条目。当我在 tomcat 中运行并调用该服务时,我收到一条错误消息,指出第二个 bean(保存在控制器中)不是唯一的

No unique bean of type [com.hp.it.km.search.web.suggestion.SuggestionService] is defined: expected single matching bean but found 2: [suggestionService, SuggestionService]

I cannot see where I am defining the bean twice however am new to Spring and autowiring so I may be missing something fundamental. Source code for xml and 2 class listed below...

我看不到我在哪里定义了 bean 两次,但是我是 Spring 和自动装配的新手,所以我可能会遗漏一些基本的东西。下面列出了 xml 和 2 类的源代码...

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"     xmlns:context="http://www.springframework.org/schema/context"     xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<context:component-scan base-package="com.hp.it.km.search.web.suggestion" />
<mvc:annotation-driven />
<context:annotation-config />

<bean id="SuggestionController" class="com.hp.it.km.search.web.suggestion.SuggestionController">
    <property name="service">
        <ref bean="SuggestionService" />
    </property>
</bean>

<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
    <property name="indexSearchers"> 
         <map>
            <entry key="KMSearcher"> <ref bean="KMSearcherBean"></ref></entry>
        </map>
    </property>
</bean>

<bean id="KMSearcherBean" class="com.hp.it.km.search.web.suggestion.SuggestionIndexSearcher">
      <constructor-arg index="0" value="KMSearcher" />
      <constructor-arg index="1" value="C://dev//workspace//search-restful-webapp//src//main//resources//indexes//keyword" />
</bean>

The class asscoaites with the autowired controller and service bean are here...

带有自动装配控制器和服务 bean 的类 asscoaites 在这里......

@Controller
public class SuggestionController {
private SuggestionService service;

@Autowired
public void setService(SuggestionService service) {
    this.service = service;
}

public SuggestionService getService() {
    return service;
}

and...

和...

@Component
public class SuggestionService {

private Map<String, IndexSearcher> indexSearchers = new HashMap<String,      IndexSearcher>();

@Autowired
public void setIndexSearchers(Map<String, IndexSearcher> indexSearchers) {
    this.indexSearchers = indexSearchers;
}

    public SuggestionService() {
    super(); }

Please Help!

请帮忙!

回答by Aravind A

The issue is because you have a bean of type SuggestionService created through @Component annotation and also through the XML config . As explained by JB Nizet, this will lead to the creation of a bean with name 'suggestionService' created via @Component and another with name 'SuggestionService' created through XML .

问题是因为您有一个 SuggestionService 类型的 bean 通过 @Component 注释和 XML config 创建。正如 JB Nizet 所解释的,这将导致创建一个名为 'suggestionService' 的 bean 通过 @Component 创建,另一个名为 'SuggestionService' 的 bean 通过 XML 创建。

When you refer SuggestionService by @Autowired, in your controller, Spring autowires "by type" by default and find two beans of type 'SuggestionService'

当您通过 @Autowired 引用 SuggestionService 时,在您的控制器中,Spring 默认“按类型”自动装配并找到两个类型为“SuggestionService”的 bean

You could do the following

您可以执行以下操作

  1. Remove @Component from your Service and depend on mapping via XML - Easiest
  2. Remove SuggestionService from XML and autowire the dependencies - use util:map to inject the indexSearchers map.
  3. Use @Resource instead of @Autowired to pick the bean by its name .

    @Resource("suggestionService")
    private SuggestionService service;
    
  1. 从您的服务中删除 @Component 并依赖于通过 XML 的映射 - 最简单
  2. 从 XML 中删除 SuggestionService 并自动装配依赖项 - 使用 util:map 注入 indexSearchers 映射。
  3. 使用 @Resource 而不是 @Autowired 来按名称选择 bean。

    @Resource("suggestionService")
    private SuggestionService service;
    

or

或者

    @Resource("SuggestionService")
    private SuggestionService service;

both should work.The third is a dirty fix and it's best to resolve the bean conflict through other ways.

两者都应该工作。第三个是一个肮脏的修复,最好通过其他方式解决 bean 冲突。

回答by danny.lesnik

If you have 2 beans of the same class autowired to one class you shoud use @Qualifier(Spring Autowiring @Qualifier example).

如果您有 2 个相同类的 bean 自动连接到您应该使用的一个类@QualifierSpring Autowiring @Qualifier 示例)。

But it seems like your problem comes from incorrect Java Syntax.

但似乎您的问题来自不正确的 Java 语法。

Your object should start with lower case letter

您的对象应以小写字母开头

SuggestionService suggestion;

Your setter should start with lower case as well and object name should be with Upper case

你的 setter 也应该以小写开头,对象名称也应该以大写开头

public void setSuggestion(final Suggestion suggestion) {
    this.suggestion = suggestion;
}

回答by vsingh

For me it was case of having two beans implementing the same interface. One was a fake ban for the sake of unit test which was conflicting with original bean. If we use

对我来说,这是让两个 bean 实现相同接口的情况。一个是为了单元测试的假禁令,与原始 bean 相冲突。如果我们使用

@component("suggestionServicefake")

@component("suggestionServicefake")

, it still references with suggestionService. So I removed @component and only used

,它仍然引用suggestService。所以我删除了@component 并且只使用了

@Qualifier("suggestionServicefake")

@Qualifier("suggestionServicefake")

which solved the problem

这解决了问题

回答by JB Nizet

If I'm not mistaken, the default bean name of a bean declared with @Component is the name of its class its first letter in lower-case. This means that

如果我没记错的话,用@Component 声明的 bean 的默认 bean 名称是它的类的名称,它的第一个字母小写。这意味着

@Component
public class SuggestionService {

declares a bean of type SuggestionService, and of name suggestionService. It's equivalent to

声明一个类型为SuggestionService、名称为 的 bean suggestionService。它相当于

@Component("suggestionService")
public class SuggestionService {

or to

或者

<bean id="suggestionService" .../>

You're redefining another bean of the same type, but with a different name, in the XML:

您正在 XML 中重新定义另一个相同类型但名称不同的 bean:

<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
    ...
</bean>

So, either specify the name of the bean in the annotation to be SuggestionService, or use the ID suggestionServicein the XML (don't forget to also modify the <ref>element, or to remove it, since it isn't needed). In this case, the XML definition will override the annotation definition.

因此,要么在注释中指定 bean 的名称,要么在 XML 中SuggestionService使用 ID suggestionService(不要忘记同时修改该<ref>元素,或者将其删除,因为它不需要)。在这种情况下,XML 定义将覆盖注释定义。