29

我想自动调用一些bean(用于依赖注入)使用Spring的Web应用程序。一个控制器bean包含另一个bean,后者又保存另一个bean集合的hashmap。目前地图只有一个条目。当我在Tomcat的运行和调用服务,我得到一个错误,指出第二个bean(控制器持有)不是唯一的春天自动装配与独特的豆:春天预计单个匹配豆,但发现2

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

我不能看到我定义的豆但是两次是新来春自动装配,所以我可能会失去一些根本性的东西。 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> 

类asscoaites与自动装配Autowired控制器和服务豆在这里......

@Controller 
public class SuggestionController { 
private SuggestionService service; 

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

public SuggestionService getService() { 
    return service; 
} 

和...

@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(); } 

请帮忙!

回答

40

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

当你提到SuggestionService通过@Autowired,在你的控制器,春autowires“按类型”在默认情况下,找到类型的两个豆“SuggestionService”

你可以做以下

  1. 删除@从您的服务组件,并依靠通过XML映射 - 最简单
  2. 从XML中去除SuggestionService并自动装入依赖关系 - 使用util:map来注入indexSearchers映射。
  3. 使用@Resource而不是@Autowired来按名称选择bean。

    @Resource("suggestionService") 
    private SuggestionService service; 
    

@Resource("SuggestionService") 
    private SuggestionService service; 

都应该work.The第三是一个肮脏的修复,它是最好的解决通过其他途径豆冲突。

+0

Brilliant我只是从服务类中删除组件。然后得到一个有关控制器注册两次的错误,并通过删除组件扫描按照此解决方案http://stackoverflow.com/a/4804417/491196感谢您的帮助 –

5

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

@Component 
public class SuggestionService { 

声明SuggestionService类型的豆,并将其命名suggestionService的。这相当于

@Component("suggestionService") 
public class SuggestionService { 

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

你重新定义了同类型的另一豆,但有不同的名称,在XML:

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

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

+0

对不起,我不完全听懂你的第一句话它有点strangly写的。为什么“@Component public class SuggestionService {”和xml中的bean声明了两个bean? –

+0

在最后一句话中,你说“要么在注释中指定bean的名称是SuggestionService”是不是我所拥有的?我试着将xml bean定义更改为小写,但问题仍然存在。 Thansk为你提供帮助:) –

+0

我的编辑应该让它更清晰。 –

13

如果您有两个相同类自动装配的豆类,您应该使用@QualifierSpring Autowiring @Qualifier example)。

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

你的对象应该与小写字母开头

SuggestionService suggestion; 

你的二传手应该具有较低的情况下启动,以及和对象名称应以大写字母

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

您有关设置者名称和大小写的权利。我必须改变这个错误,而摆弄它使其工作。不幸的是,它似乎没有问题。我用正确的setter更新了上述问题。 –

6

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

@Component( “suggestionServicefake”)

,但它仍然与suggestionService引用。 所以我删除@Component和仅用于

@Qualifier( “suggestionServicefake”)

这解决了这个问题

+0

如果您使用属性@SpringBootTest( classes = SuggestionService.class)。 – DocDbg