Spring autwiring с уникальным beans: spring ожидаемым однократным сопоставлением bean, но найдено 2
Я пытаюсь autwire некоторые beans (для инъекции зависимостей), используя Spring для webapp. Один контроллер bean содержит другой bean, который, в свою очередь, содержит хэш-карту другого набора beans. Пока на карте только одна запись. Когда я запускаю 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]
Я не вижу, где я определяю 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>
Класс asscoaites с автоподвешенным контроллером и сервисом 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(); }
Пожалуйста, помогите!
Ответы
Ответ 1
Проблема заключается в том, что у вас есть bean типа SuggestionService, созданный с помощью аннотации @Component, а также через конфигурацию XML. Как пояснил JB Nizet, это приведет к созданию bean с именем "suggestionService", созданным с помощью @Component, а другое с именем "SuggestionService", созданным с помощью XML.
Когда вы ссылаетесь на SuggestionService на @Autowired, в вашем контроллере, Spring autwires "по типу" по умолчанию и найдите два beans типа 'SuggestionService'
Вы можете сделать следующее
- Удалить @Component из вашей службы и зависеть от сопоставления через XML - Самый простой
- Удалить службу предложений из XML и выполнить аутсорсинг зависимостей - используйте утилиту: map, чтобы ввести карту indexSearchers.
-
Используйте @Resource вместо @Autowired, чтобы выбрать bean по его имени.
@Resource("suggestionService")
private SuggestionService service;
или
@Resource("SuggestionService")
private SuggestionService service;
оба должны работать. Третье - грязное исправление, и лучше всего разрешить конфликт bean другими способами.
Ответ 2
Если у вас есть 2 beans того же класса, что и для одного класса, вы используете @Qualifier
(Spring Пример Autowiring @Qualifier).
Но похоже, что ваша проблема связана с неправильным синтаксисом Java.
Ваш объект должен начинаться с строчной буквы
SuggestionService suggestion;
Ваш сеттер должен начинаться с нижнего регистра, а имя объекта должно быть с верхним регистром
public void setSuggestion(final Suggestion suggestion) {
this.suggestion = suggestion;
}
Ответ 3
Для меня это был случай, когда два beans реализовали один и тот же интерфейс. Один из них был поддельным запретом на unit test, который противоречил оригиналу bean.
Если мы используем
@component ( "suggestionServicefake" )
он все еще ссылается на suggestionService.
Поэтому я удалил @component и использовал только
@Qualifier ( "suggestionServicefake" )
который решил проблему
Ответ 4
Если я не ошибаюсь, имя bean по умолчанию bean, объявленное с @Component, является именем его класса его первой буквы в нижнем регистре. Это означает, что
@Component
public class SuggestionService {
объявляет bean типа SuggestionService
и имени SuggestionService
. Это эквивалентно
@Component("suggestionService")
public class SuggestionService {
или
<bean id="suggestionService" .../>
Вы переопределяете еще один bean того же типа, но с другим именем в XML:
<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
...
</bean>
Итак, укажите имя bean в аннотации как SuggestionService
или используйте идентификатор SuggestionService
в XML (не забудьте также изменить элемент <ref>
или удалить он, поскольку он не нужен). В этом случае определение XML переопределит определение аннотации.