J'essaie d'autowire quelques haricots (pour l'injection de dépendance) en utilisant Spring pour une application Web. Un bean contrôleur contient un autre bean qui contient à son tour une hashmap d'un autre ensemble de beans. Pour l'instant, la carte n'a qu'une entrée. Lorsque j'exécute Tomcat et que j'appelle le service, un message d'erreur s'affiche: le second bean (conservé dans le contrôleur) n'est pas unique.
No unique bean of type [com.hp.it.km.search.web.suggestion.SuggestionService] is defined: expected single matching bean but found 2: [suggestionService, SuggestionService]
Je ne vois pas où je suis en train de définir deux fois le haricot, mais je suis nouveau pour Spring et le transfert automatique, de sorte que je risque de manquer quelque chose de fondamental. Code source pour xml et 2 classes listés ci-dessous ...
<?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>
La classe asscoaites avec le contrôleur auto-câblé et le haricot de service sont ici ...
@Controller
public class SuggestionController {
private SuggestionService service;
@Autowired
public void setService(SuggestionService service) {
this.service = service;
}
public SuggestionService getService() {
return service;
}
et...
@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(); }
S'il vous plaît aider!
Le problème vient du fait que vous avez un bean de type SuggestionService créé via l'annotation @Component et également via la configuration XML. Comme expliqué par JB Nizet, cela conduira à la création d'un bean avec le nom 'suggestionService' créé via @Component et un autre avec le nom 'SuggestionService' créé via XML.
Lorsque vous référencez SuggestionService par @Autowired, dans votre contrôleur, les relais automatiques de ressort "par type" par défaut et recherchez deux beans de type "SuggestionService".
Vous pouvez faire ce qui suit
Utilisez @Resource au lieu de @Autowired pour sélectionner le bean par son nom.
@Resource("suggestionService")
private SuggestionService service;
ou
@Resource("SuggestionService")
private SuggestionService service;
les deux devraient fonctionner. La troisième solution est une solution sale et il est préférable de résoudre le conflit de haricots par d'autres moyens.
Si vous avez 2 beans de la même classe, vous devez utiliser @Qualifier
_ ( Exemple de Spring Autowiring @Qualifier ).
Mais il semble que votre problème provienne d'une syntaxe incorrecte Java.
Votre objet devrait commencer par une lettre minuscule
SuggestionService suggestion;
Votre poseur doit également commencer par une minuscule et le nom de l'objet par une majuscule.
public void setSuggestion(final Suggestion suggestion) {
this.suggestion = suggestion;
}
Si je ne me trompe pas, le nom de bean par défaut d'un bean déclaré avec @Component est le nom de sa classe, sa première lettre en minuscule. Cela signifie que
@Component
public class SuggestionService {
déclare un haricot de type SuggestionService
et de nom suggestionService
. C'est équivalent à
@Component("suggestionService")
public class SuggestionService {
ou pour
<bean id="suggestionService" .../>
Vous redéfinissez un autre haricot du même type, mais avec un nom différent, dans le XML:
<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
...
</bean>
Donc, spécifiez le nom du bean dans l'annotation comme étant SuggestionService
ou utilisez l'ID suggestionService
dans le code XML (n'oubliez pas de modifier également le <ref>
élément, ou pour le supprimer, puisqu'il n'est pas nécessaire). Dans ce cas, la définition XML remplacera la définition d'annotation.
Pour moi, il s'agissait de deux beans implémentant la même interface. L'un d'entre eux était une fausse interdiction pour le test unitaire qui était en conflit avec le haricot d'origine. Si on utilise
@component ("suggestionServicefake")
, il fait toujours référence à suggestionService. J'ai donc retiré @component et utilisé seulement
@Qualifier ("suggestionServicefake")
qui a résolu le problème