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