@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 <maciej@radzikowski.com.pl>
 */
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?


¿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.


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.


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"})

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.


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;


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 {
}

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.



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í.


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 {

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

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.


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.


0

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


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.