29

Estoy tratando de Autowire algunos granos (por inyección de dependencias) usando primavera para una aplicación web. Un control bean contiene otro bean que a su vez contiene un hashmap de otro conjunto de beans. Por ahora, el mapa solo tiene una entrada. Cuando corro en Tomcat y llamar al servicio me da un error diciendo que la segunda frijol (que tuvo lugar en el controlador) no es únicaautowiring primavera con las habas únicas: frijol juego único resorte de esperar, pero encontrado 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] 

no puedo ver donde estoy definiendo el grano dos veces, sin embargo soy nuevo en primavera y autocableando así que me puede estar perdiendo algo fundamental. El código fuente de la clase XML y 2 se enumeran a continuación ...

<?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> 

Los asscoaites clase con el controlador autowired y frijol servicio son aquí ...

@Controller 
public class SuggestionController { 
private SuggestionService service; 

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

public SuggestionService getService() { 
    return service; 
} 

y ...

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

Por favor, ayuda!

Respuesta

40

La cuestión es porque tiene una Bean de tipo SuggestionService creado a través de la anotación @Component y también a través de la configuración XML. Como se explica por JB Nizet, esto dará lugar a la creación de un grano con el nombre 'suggestionService' creada a través de @Component y otro con el nombre 'SuggestionService' creada a través de XML.

Cuando se hace referencia SuggestionService por @Autowired, en su controlador, autowires la Primavera "de tipo" por defecto y encontrar dos granos de tipo 'SuggestionService'

Se podría hacer lo siguiente

  1. Retire @ Componente de su Servicio y dependa del mapeo a través de XML - Más fácil
  2. Elimine SuggestionService de XML y autoelene las dependencias - use util: map para inyectar el mapa de indexSearch.
  3. Usa @Resource en lugar de @Autowired para elegir el bean por su nombre.

    @Resource("suggestionService") 
    private SuggestionService service; 
    

o

@Resource("SuggestionService") 
    private SuggestionService service; 

ambos deben work.The tercera es una solución sucio y lo mejor es resolver el conflicto de frijol a través de otras maneras.

+0

Brillante Simplemente eliminé el componente de la clase de servicio. Luego recibí un error sobre el controlador que se está registrando dos veces y solucioné esto eliminando el escaneo de componentes según esta solución http://stackoverflow.com/a/4804417/491196 Gracias por su ayuda –

5

Si no me equivoco, el nombre de beans predeterminada de un grano declarada con @Component es el nombre de su clase con su primera letra en minúscula. Esto significa que

@Component 
public class SuggestionService { 

declara un grano de tipo SuggestionService, y del nombre suggestionService. Es equivalente a

@Component("suggestionService") 
public class SuggestionService { 

o para

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

Usted está redefiniendo otro bean del mismo tipo, pero con un nombre diferente, en el XML:

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

Así que, ya sea especifique el nombre del grano en la anotación para ser SuggestionService, o utilizar el ID de suggestionService en el XML (no se olvide de modificar también el elemento <ref>, o para eliminarlo, ya que no es necesario). En este caso, la definición XML anulará la definición de la anotación.

+0

siento Que te comprendo muy bien su primera frase es un poco strangly escrito. ¿Por qué "@Component public class SuggestionService {" y el bean en el xml declaran dos beans? –

+0

En su última frase dice "especifique el nombre del bean en la anotación para que sea SuggestionService" ¿no es esto lo que tengo? Traté de cambiar la definición de xml bean en minúsculas, pero el problema persistió. Thansk por su ayuda :) –

+0

Mis ediciones deberían hacerlo más claro. –

13

Si tiene 2 granos de la misma clase autoconectados a una clase, debe usar @Qualifier (Spring Autowiring @Qualifier example).

pero parece que el problema viene de Java Sintaxis incorrecta.

Su objeto debe comenzar con letra minúscula

SuggestionService suggestion; 

Su colocador debe comenzar con minúsculas, así y nombre de objeto debe ser con mayúsculas

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

Su derecho sobre el nombre y las mayúsculas del colocador. Debo haber cambiado esto incorrectamente mientras jugueteaba con él para que funcione. Lamentablemente, no parece ser el problema. He actualizado la pregunta anterior con el colocador correcto. –

6

Para mí fue el caso de tener dos beans implementando la misma interfaz. Una era una prohibición falsa por el bien de la prueba unitaria que estaba en conflicto con el frijol original. Si utilizamos

@component ("suggestionServicefake")

, todavía con referencias suggestionService. Quité tan @component y sólo se utiliza

@Qualifier ("suggestionServicefake")

que solucionó el problema

+0

Lo mismo si usa la propiedad @SpringBootTest (classes = SuggestionService.class) en su clase de prueba. – DocDbg

Cuestiones relacionadas