使用独特bean进行Spring自动装配:Spring期望单个匹配bean但找到2

Rob*_*ely 43 spring annotations dependency-injection spring-mvc autowired

我正在尝试使用Spring为webapp自动装配一些bean(用于依赖注入).一个控制器bean包含另一个bean,而另一个bean又拥有另一组bean的hashmap.目前,地图只有一个条目.当我在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]
Run Code Online (Sandbox Code Playgroud)

我无法看到我在两次定义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>
Run Code Online (Sandbox Code Playgroud)

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

@Controller
public class SuggestionController {
private SuggestionService service;

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

public SuggestionService getService() {
    return service;
}
Run Code Online (Sandbox Code Playgroud)

和...

@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(); }
Run Code Online (Sandbox Code Playgroud)

请帮忙!

Ara*_*d A 56

问题是因为你有一个通过@Component注释创建的SuggestionService类型的bean,也通过XML配置创建.正如JB Nizet所解释的那样,这将导致创建一个名为'suggestionService'的bean,它通过@Component创建,另一个名为'SuggestionService',通过XML创建.

当您通过@Autowired引用SuggestionService时,在您的控制器中,Spring默认自动"按类型"自动查找两个类型为'SuggestionService'的bean

您可以执行以下操作

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

    @Resource("suggestionService")
    private SuggestionService service;
    
    Run Code Online (Sandbox Code Playgroud)

要么

    @Resource("SuggestionService")
    private SuggestionService service;
Run Code Online (Sandbox Code Playgroud)

两者都应该有效.第三个是脏修复,最好通过其他方式解决bean冲突.


dan*_*nik 15

如果你有两个相同类的bean自动连接到一个类,你应该使用@Qualifier(Spring Autowiring @Qualifier示例).

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

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

SuggestionService suggestion;
Run Code Online (Sandbox Code Playgroud)

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

public void setSuggestion(final Suggestion suggestion) {
    this.suggestion = suggestion;
}
Run Code Online (Sandbox Code Playgroud)


JB *_*zet 6

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

@Component
public class SuggestionService {
Run Code Online (Sandbox Code Playgroud)

声明一个类型SuggestionService和名称的bean suggestionService.它相当于

@Component("suggestionService")
public class SuggestionService {
Run Code Online (Sandbox Code Playgroud)

或者

<bean id="suggestionService" .../>
Run Code Online (Sandbox Code Playgroud)

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

<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
    ...
</bean>
Run Code Online (Sandbox Code Playgroud)

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


vsi*_*ngh 6

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

@Component( "suggestionServicefake")

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

@Qualifier( "suggestionServicefake")

这解决了问题

  • 如果您在测试类中使用 @SpringBootTest(classes = SuggestionService.class) 属性,则相同。 (2认同)