@Autowired: no se ha encontrado ningún bean calificado de tipo para la dependencia

89

Comencé mi proyecto creando entidades, servicios y pruebas JUnit para servicios usando Spring e Hibernate. Todo esto funciona muy bien. Luego agregué spring-mvc para hacer esta aplicación web usando muchos tutoriales paso a paso diferentes, pero cuando intento crear un controlador con la anotación @Autowired, obtengo errores de Glassfish durante la implementación. Supongo que por alguna razón Spring no ve mis servicios, pero después de muchos intentos todavía no puedo manejarlo.

Pruebas para servicios con

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml"})

y

@Autowired
MailManager mailManager;

trabaja apropiadamente.

Controladores sin @Autowired también, puedo abrir mi proyecto en el navegador web sin problemas.

/src/main/resources/beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">

    <context:property-placeholder location="jdbc.properties" />

    <context:component-scan base-package="pl.com.radzikowski.webmail">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <!--<context:component-scan base-package="pl.com.radzikowski.webmail.service" />-->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- Persistance Unit Manager for persistance options managing -->
    <bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="defaultDataSource" ref="dataSource"/>
    </bean>

    <!-- Entity Manager Factory for creating/updating DB schema based on persistence files and entity classes -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
        <property name="persistenceUnitName" value="WebMailPU"/>
    </bean>

    <!-- Hibernate Session Factory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--<property name="schemaUpdate" value="true" />-->
        <property name="packagesToScan" value="pl.com.radzikowski.webmail.domain" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            </props>
        </property>
    </bean>

    <!-- Hibernate Transaction Manager -->
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- Activates annotation based transaction management -->
    <tx:annotation-driven transaction-manager="txManager"/>

</beans>

/webapp/WEB-INF/web.xml

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="WebApp_ID" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Spring Web MVC Application</display-name>
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

/webapp/WEB-INF/mvc-dispatcher-servlet.xml

<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="pl.com.radzikowski.webmail" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <mvc:annotation-driven/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

pl.com.radzikowski.webmail.service.AbstractManager

package pl.com.radzikowski.webmail.service;

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Master Manager class providing basic fields for services.
 * @author Maciej Radzikowski <[email protected]>
 */
public class AbstractManager {

    @Autowired
    protected SessionFactory sessionFactory;

    protected final Logger logger = Logger.getLogger(this.getClass());

}

pl.com.radzikowski.webmail.service.MailManager

package pl.com.radzikowski.webmail.service;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Transactional
public class MailManager extends AbstractManager {
    // some methods...
}

pl.com.radzikowski.webmail.HomeController

package pl.com.radzikowski.webmail.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import pl.com.radzikowski.webmail.service.MailManager;

@Controller
@RequestMapping("/")
public class HomeController {

    @Autowired
    public MailManager mailManager;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String homepage(ModelMap model) {
        return "homepage";
    }

}

Error:

SEVERE:   Exception while loading the app
SEVERE:   Undeployment failed for context /WebMail
SEVERE:   Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'homeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public pl.com.radzikowski.webmail.service.MailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [pl.com.radzikowski.webmail.service.MailManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Lo siento por mucho código, pero ya no sé qué puede causar ese error.

Adicional

He creado la interfaz:

@Component
public interface IMailManager {

implementos añadidos:

@Component
@Transactional
public class MailManager extends AbstractManager implements IMailManager {

y cambiado autowired:

@Autowired
public IMailManager mailManager;

Pero todavía arroja errores (también cuando lo intenté con @Qualifier)

..No se pudo autowire campo: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

También probé con diferentes combinaciones de @Component y @Transactional.

¿No debería incluir beans.xml en web.xml de alguna manera?

Radzikowski
fuente
¿Cómo está cargando beans.xml?
Michael Wiles
ahora que tal si dejamos solo uno de MailManagerInterfacey IMailManager? :)
Patison
Lo siento, pegué mal el código. En mi programa hay en IMailManagertodas partes.
Radzikowski
ah, exactamente .. agregar <import resource="classpath:/beans.xml"/>amvc-dispatcher-servlet.xml
Patison
Por cierto, ¿probaste la decisión de @emd?
Patison

Respuestas:

81

Debería conectar automáticamente la interfaz en AbstractManagerlugar de la clase MailManager. Si tiene diferentes implementaciones AbstractManager, puede escribir @Component("mailService")y luego @Autowired @Qualifier("mailService")combinar para autowire una clase específica.

Esto se debe al hecho de que Spring crea y usa objetos proxy basados ​​en las interfaces.

Patison
fuente
2
Gracias, pero todavía no funciona (mismo error). Agregué cambios en la publicación. ¿Quizás no incluyo / busco algo en mi proyecto correctamente?
Radzikowski
Me pregunto si hay una manera de hacer algo así @Autowired AbstractManager[] abstractManagersque contenga todas sus implementaciones.
WoLfPwNeR
@WoLfPwNeR Debería funcionar exactamente como lo escribió. Ver enlace
Patison
¿Por qué no MailManager?
Alex78191
Tengo dos @Serviceclases que implementan la misma interfaz. Ambos están @Autowireden otra clase. Inicialmente causó el mismo problema que la publicación original cuando usé el tipo de clase específico. Después de esta respuesta, cambié para usar el tipo de interfaz con diferentes @Qualifier("myServiceA")y @Qualifier("myServiceB"), y el problema se resolvió. ¡Gracias!
xialin
27

Esto sucedió porque mis pruebas no estaban en el mismo paquete que mis componentes. (Había cambiado el nombre de mi paquete de componentes, pero no de mi paquete de prueba). Y lo estaba usando @ComponentScanen mi @Configurationclase de prueba , por lo que mis pruebas no encontraban los componentes en los que se basaban.

Por lo tanto, vuelva a verificar si obtiene este error.

amarrados
fuente
2
Esto funcionó para mí. Mis pruebas fallaron cuando refactoricé el código para cambiarlo a un nuevo nombre de paquete porque estaba usando el nombre de paquete antiguo en @ComponentScan.
Vijay Vepakomma
1
¿Cómo usar la @Configurationclase desde src/mainadentro src/test?
Alex78191
10

La cuestión es que tanto el contexto de la aplicación como el contexto de la aplicación web se registran en WebApplicationContext durante el inicio del servidor. Cuando ejecuta la prueba, debe indicar explícitamente qué contextos cargar.

Prueba esto:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml", "/mvc-dispatcher-servlet.xml"})
emd
fuente
1
¿Cómo hacerlo si estoy usando Spring Boot?
Alex78191
Me olvido de configurar el análisis de componentes para las dependencias de maven y lucho con esto como una vez al año.
b15
Si está hablando de la aplicación en sí y no de pruebas de integración, para Spring boot puede hacerlo así: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15
5

¡Pasé mucho de mi tiempo con esto! ¡Culpa mía! Más tarde descubrí que la clase en la que declaré la anotación Serviceo Componentera de tipo abstracto. Había habilitado los registros de depuración en Springframework pero no se recibió ninguna pista. Compruebe si la clase es de tipo abstracto. Si entonces, se aplica la regla básica, no se puede instanciar una clase abstracta.

James Jithin
fuente
1
¡Me salvó el día, señor, esto es tan difícil de detectar!
Japheth Ongeri - inkalimeva
3

Enfrentaba el mismo problema al cablear automáticamente la clase desde uno de mis archivos jar. Solucioné el problema usando la anotación @Lazy:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;

Ved Singh
fuente
2

La forma correcta será conectar automáticamente AbstractManager, como sugirió Max, pero esto también debería funcionar bien.

@Autowired
@Qualifier(value="mailService")
public MailManager mailManager;

y

@Component("mailService")
@Transactional
public class MailManager extends AbstractManager {
}
Abhishek Anand
fuente
2

Me encontré con esto recientemente y resultó que importé la anotación incorrecta en mi clase de servicio. Netbeans tiene una opción para ocultar las declaraciones de importación, por eso no lo vi durante algún tiempo.

He usado en @org.jvnet.hk2.annotations.Servicelugar de @org.springframework.stereotype.Service.

Kazmer
fuente
1
  • Una de las razones por las que BeanB puede no existir en el contexto
  • Otra causa de la excepción es la existencia de dos frijoles
  • O las definiciones en el bean de contexto que no están definidas se solicitan por nombre del contexto de Spring

ver más esta url:

http://www.baeldung.com/spring-nosuchbeandefinitionexception

zohreh
fuente
1
 <context:component-scan base-package="com.*" />

Llegó el mismo problema, lo resolví manteniendo las anotaciones intactas y en el despachador servlet :: manteniendo el escaneo del paquete base ya que com.*.esto funcionó para mí.

Ramanpreet Singh
fuente
1

Esto puede ayudarlo a:

Tengo la misma excepción en mi proyecto. Después de buscar, descubrí que me falta la anotación @Service en la clase donde estoy implementando la interfaz que quiero @Autowired.

En su código, puede agregar la anotación @Service a la clase MailManager.

@Transactional
@Service
public class MailManager extends AbstractManager implements IMailManager {
Akshay Pethani
fuente
La @Serviceanotación contiene @Component. Tener ambos es redundante.
AnthonyW
1

En lugar de @Autowire MailManager mailManager, puede simular el bean como se indica a continuación:

import org.springframework.boot.test.mock.mockito.MockBean;

::
::

@MockBean MailManager mailManager;

Además, puede configurar por @MockBean MailManager mailManager;separado en la @SpringBootConfigurationclase e inicializar como se muestra a continuación:

@Autowire MailManager mailManager
Barani r
fuente
1

Enfrenté el mismo problema en mi aplicación de arranque de primavera a pesar de que tenía habilitados los escaneos específicos de mi paquete como

@SpringBootApplication(scanBasePackages={"com.*"})

Pero, el problema se resolvió proporcionando @ComponentScan({"com.*"})en mi clase de aplicación.

Rajish Nair
fuente
0

Mi conjetura es que aqui

<context:component-scan base-package="pl.com.radzikowski.webmail" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

todas las anotaciones se desactivan primero mediante use-default-filters = "false" y luego solo se activa la anotación @Controller. Por lo tanto, su anotación @Component no está habilitada.

LoBo
fuente
0

Si está probando su controlador. No olvide usar @WebAppConfiguration en su clase de prueba.

Joao Luiz Cadore
fuente
0

Esto sucedió porque agregué una dependencia cableada automáticamente a mi clase de servicio, pero olvidé agregarla a los simulacros inyectados en mi prueba de unidad de servicio.

La excepción de la prueba unitaria pareció informar un problema en la clase de servicio cuando el problema estaba realmente en la prueba unitaria. En retrospectiva, el mensaje de error me dijo exactamente cuál era el problema.

Curtis Yallop
fuente