web-dev-qa-db-ja.com

ユニークなBeanを使用した春の自動配線:Springは単一の一致するBeanを予期していましたが、見つかった2

Spring for webappを使用して、いくつかのBean(依存性注入用)を自動配線しようとしています。 1つのコントローラーBeanには別のBeanが含まれ、別のBeanには別のBeanセットのハッシュマップが保持されます。現在のところ、マップには1つのエントリしかありません。 Tomcatで実行してサービスを呼び出すと、2番目の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]

Beanを2回定義している場所がわかりませんが、Springとautowiringが初めてなので、基本的なものが不足している可能性があります。以下にリストされている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>

自動配線されたコントローラーとサービスBeanを使用したクラスの関連付けはここにあります...

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

助けてください!

41
Rob McFeely

問題は、@ ComponentアノテーションおよびXML configを通じてSuggestionServiceタイプのBeanが作成されているためです。 JB Nizetが説明したように、これは@Componentを介して作成された 'suggestionService'という名前のBeanと、XMLを介して作成された 'SuggestionService'という名前のBeanの作成につながります。

コントローラーでSuggestionServiceを@Autowiredで参照すると、Springはデフォルトで「タイプ別」に自動配線し、「SuggestionService」タイプの2つのBeanを見つけます。

次のことができます

  1. サービスから@Componentを削除し、XMLを介したマッピングに依存する-最も簡単な
  2. SuggestionServiceをXMLから削除し、依存関係を自動配線します。util:mapを使用してindexSearchersマップを挿入します。
  3. 名前でBeanを選択するには、@ Autowiredの代わりに@Resourceを使用します。

    @Resource("suggestionService")
    private SuggestionService service;
    

または

    @Resource("SuggestionService")
    private SuggestionService service;

3番目は汚い修正であり、他の方法でBeanの競合を解決するのが最善です。

54
Aravind A

同じクラスの2つのBeanが1つのクラスに自動配線されている場合は、@Qualifierスプリング自動配線@修飾子の例 )。

しかし、あなたの問題は間違ったJava Syntax。

オブジェクトは小文字で始める必要があります

SuggestionService suggestion;

セッターも小文字で始まり、オブジェクト名は大文字である必要があります

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

間違っていなければ、@ Componentで宣言されたBeanのデフォルトのBean名は、クラスの最初の文字が小文字のクラスの名前です。この意味は

@Component
public class SuggestionService {

タイプSuggestionService、および名前suggestionServiceのBeanを宣言します。それは同等です

@Component("suggestionService")
public class SuggestionService {

または

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

XMLで、同じタイプの別のBeanを別の名前で再定義しています。

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

したがって、アノテーションでBeanの名前をSuggestionServiceに指定するか、XMLでID suggestionServiceを使用します(<ref>要素も変更することを忘れないでください。または、削除する必要はありません)。この場合、XML定義は注釈定義をオーバーライドします。

6
JB Nizet

私にとっては、2つのBeanが同じインターフェースを実装している場合でした。 1つは、元のBeanと競合する単体テストのための偽の禁止でした。使用する場合

@component( "suggestionServicefake")

、suggestionServiceで引き続き参照します。だから私は@componentを削除し、使用しただけ

@Qualifier( "suggestionServicefake")

問題を解決しました

6
vsingh