@Autowired - Nessun bean qualificante di tipo trovato per la dipendenza


89

Ho iniziato il mio progetto creando entità, servizi e test JUnit per i servizi utilizzando Spring e Hibernate. Tutto questo funziona alla grande. Quindi ho aggiunto spring-mvc per rendere questa applicazione web utilizzando molti diversi tutorial passo-passo, ma quando provo a creare Controller con l'annotazione @Autowired, ricevo errori da Glassfish durante la distribuzione. Immagino che per qualche motivo Spring non veda i miei servizi, ma dopo molti tentativi ancora non riesco a gestirlo.

Test per servizi con

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

e

@Autowired
MailManager mailManager;

funziona correttamente.

Anche i controller senza @Autowired, posso aprire il mio progetto nel browser web senza problemi.

/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";
    }

}

Errore:

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

Ci scusiamo per molto codice, ma non so più cosa possa causare quell'errore.

Aggiunto

Ho creato l'interfaccia:

@Component
public interface IMailManager {

attrezzi aggiunti:

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

e cambiato autowired:

@Autowired
public IMailManager mailManager;

Ma genera ancora errori (anche quando ho provato con @Qualifier)

..Campo non autowire possibile: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

Ho provato anche con diverse combinazioni di @Component e @Transactional.

Non dovrei includere in qualche modo bean.xml in web.xml?


Come stai caricando bean.xml?
Michael Wiles

ora che ne dici di lasciare solo uno di MailManagerInterfacee IMailManager? :)
Patison

Scusa, ho incollato male il codice. Nel mio programma c'è IMailManagerovunque.
Radzikowski

ah, esattamente .. aggiungi <import resource="classpath:/beans.xml"/>amvc-dispatcher-servlet.xml
Patison

A proposito, hai provato la decisione @emd?
Patison

Risposte:


81

Dovresti autowire l'interfaccia AbstractManagerinvece di class MailManager. Se hai diverse implementazioni AbstractManagerpuoi scrivere @Component("mailService")e poi @Autowired @Qualifier("mailService")combinare per autowire una classe specifica.

Ciò è dovuto al fatto che Spring crea e utilizza oggetti proxy basati sulle interfacce.


2
Grazie ma ancora non funziona (stesso errore). Ho aggiunto modifiche in post. Forse non includo / cerco qualcosa nel mio progetto correttamente?
Radzikowski

Mi chiedo se esiste un modo per fare qualcosa del genere @Autowired AbstractManager[] abstractManagersche contenga tutte le sue implementazioni.
WoLfPwNeR

@WoLfPwNeR Dovrebbe funzionare esattamente come hai scritto. Vedi link
Patison

Perché no MailManager?
Alex78191

Ho due @Serviceclassi che implementano la stessa interfaccia. Entrambi sono @Autowiredin un'altra classe. Inizialmente ha causato lo stesso problema del post originale quando ho usato il tipo di classe specifico. A seguito di questa risposta, ho cambiato per utilizzare il tipo di interfaccia con diversi @Qualifier("myServiceA")e @Qualifier("myServiceB")e il problema è stato risolto. Grazie!
xialin

27

Mi è successo perché i miei test non erano nello stesso pacchetto dei miei componenti. (Avevo rinominato il mio pacchetto di componenti, ma non il mio pacchetto di test.) E stavo usando @ComponentScannella mia @Configurationclasse di test , quindi i miei test non trovavano i componenti su cui si basavano.

Quindi, ricontrolla se ricevi questo errore.


2
Questo ha funzionato per me. I miei test non sono riusciti quando ho modificato il codice per passare a un nuovo nome di pacchetto perché stavo usando il vecchio nome di pacchetto in @ComponentScan.
Vijay Vepakomma

1
Come usare la @Configurationclasse da src/mainin src/test?
Alex78191

10

Il fatto è che sia il contesto dell'applicazione che il contesto dell'applicazione Web vengono registrati in WebApplicationContext durante l'avvio del server. Quando esegui il test devi indicare esplicitamente quali contesti caricare.

Prova questo:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml", "/mvc-dispatcher-servlet.xml"})

1
Come farlo se sto usando Spring Boot?
Alex78191

Mi dimentico di configurare la scansione dei componenti per le dipendenze maven e combatto con questo come una volta all'anno.
b15

Se stai parlando dell'applicazione stessa e non dei test di integrazione, per Spring boot puoi farlo in questo modo: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15

5

Ho passato molto del mio tempo con questo! Colpa mia! Successivamente ho scoperto che la classe su cui ho dichiarato l'annotazione Serviceo Componentera di tipo astratto. Aveva abilitato i log di debug su Springframework ma non è stato ricevuto alcun suggerimento. Controlla se la classe è di tipo astratto. Se poi, la regola di base applicata, non è possibile istanziare una classe astratta.


1
Mi hai salvato la giornata, signore, è così difficile da rilevare!
Japheth Ongeri - inkalimeva


3

Stavo affrontando lo stesso problema durante il cablaggio automatico della classe da uno dei miei file jar. Ho risolto il problema utilizzando l'annotazione @Lazy:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;


2

Il modo corretto dovrebbe essere quello di autowire AbstractManager, come suggerito da Max, ma anche questo dovrebbe funzionare bene.

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

e

@Component("mailService")
@Transactional
public class MailManager extends AbstractManager {
}

2

Mi sono imbattuto in questo di recente e, come si è scoperto, ho importato l'annotazione sbagliata nella mia classe di servizio. Netbeans ha un'opzione per nascondere le istruzioni di importazione, ecco perché non l'ho visto per un po 'di tempo.

Ho usato @org.jvnet.hk2.annotations.Serviceinvece di @org.springframework.stereotype.Service.



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

Lo stesso problema è arrivato, l'ho risolto mantenendo intatte le annotazioni e nel servlet del dispatcher :: mantenendo la scansione del pacchetto di base poiché ha com.*.funzionato per me.


1

Questo può aiutarti:

Ho la stessa eccezione nel mio progetto. Dopo aver cercato mentre ho scoperto che mi manca l'annotazione @Service per la classe in cui sto implementando l'interfaccia che voglio @Autowired.

Nel tuo codice puoi aggiungere l'annotazione @Service alla classe MailManager.

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

L' @Serviceannotazione contiene @Component. Avere entrambi è ridondante.
AnthonyW

1

Invece di @Autowire MailManager mailManager, puoi deridere il bean come indicato di seguito:

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

::
::

@MockBean MailManager mailManager;

Inoltre, puoi configurare @MockBean MailManager mailManager;separatamente nella @SpringBootConfigurationclasse e inizializzare come di seguito:

@Autowire MailManager mailManager

1

Ho affrontato lo stesso problema nella mia applicazione di avvio primaverile anche se avevo abilitato le scansioni specifiche del mio pacchetto come

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

Tuttavia, il problema è stato risolto fornendo @ComponentScan({"com.*"})nella mia classe Application.


0

La mia ipotesi è che qui

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

tutte le annotazioni vengono prima disabilitate da use-default-filters = "false" e poi solo l'annotazione @Controller abilitata. Pertanto, l'annotazione @Component non è abilitata.


0

Se stai testando il tuo controller. Non dimenticare di usare @WebAppConfiguration nella tua classe di test.


0

Questo è accaduto perché ho aggiunto una dipendenza cablata automaticamente alla mia classe di servizio ma ho dimenticato di aggiungerla ai mock iniettati nel mio test unitario di servizio.

L'eccezione dello unit test sembrava segnalare un problema nella classe di servizio quando il problema era effettivamente nello unit test. In retrospettiva, il messaggio di errore mi ha detto esattamente qual era il problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.