@Autowired - Aucun bean éligible de type trouvé pour la dépendance

89

J'ai commencé mon projet en créant des entités, des services et des tests JUnit pour les services utilisant Spring et Hibernate. Tout cela fonctionne très bien. Ensuite, j'ai ajouté spring-mvc pour créer cette application Web à l'aide de nombreux didacticiels étape par étape, mais lorsque j'essaie de créer Controller avec l'annotation @Autowired, j'obtiens des erreurs de Glassfish lors du déploiement. Je suppose que pour une raison quelconque, Spring ne voit pas mes services, mais après de nombreuses tentatives, je ne peux toujours pas le gérer.

Tests pour les services avec

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

et

@Autowired
MailManager mailManager;

fonctionne correctement.

Contrôleurs sans @Autowired aussi, je peux ouvrir mon projet dans un navigateur Web sans problème.

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

}

Erreur:

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

Désolé pour beaucoup de code, mais je ne sais plus ce qui peut causer cette erreur.

Ajoutée

J'ai créé l'interface:

@Component
public interface IMailManager {

outils ajoutés:

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

et changé autowired:

@Autowired
public IMailManager mailManager;

Mais cela génère toujours des erreurs (même lorsque j'ai essayé avec @Qualifier)

..Ne peut pas utiliser automatiquement le champ: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

J'ai également essayé différentes combinaisons de @Component et @Transactional.

Ne devrais-je pas inclure beans.xml dans web.xml d'une manière ou d'une autre?

Radzikowski
la source
Comment chargez-vous beans.xml?
Michael Wiles
maintenant que diriez-vous de ne laisser qu'un seul MailManagerInterfaceet IMailManager? :)
Patison
Désolé, j'ai mal collé le code. Dans mon programme, il y en a IMailManagerpartout.
Radzikowski
ah, exactement .. ajouter <import resource="classpath:/beans.xml"/>àmvc-dispatcher-servlet.xml
Patison
Au fait, avez-vous essayé la décision @emd?
Patison

Réponses:

81

Vous devriez autowire l'interface AbstractManagerau lieu de la classe MailManager. Si vous avez différentes implémentations deAbstractManager vous pouvez écrire @Component("mailService")puis les @Autowired @Qualifier("mailService")combiner pour activer automatiquement une classe spécifique.

Cela est dû au fait que Spring crée et utilise des objets proxy basés sur les interfaces.

Patison
la source
2
Merci mais ça ne marche toujours pas (même erreur). J'ai ajouté des modifications dans le message. Peut-être que je n'inclus / ne recherche pas correctement quelque chose dans mon projet?
Radzikowski
Je me demande s'il existe un moyen de faire quelque chose comme @Autowired AbstractManager[] abstractManagersça contient toutes ses implémentations.
WoLfPwNeR
@WoLfPwNeR Cela devrait fonctionner exactement comme vous l'avez écrit. Voir le lien
Patison
Pourquoi pas MailManager?
Alex78191
J'ai deux @Serviceclasses implémentant la même interface. Les deux sont @Autowireddans une autre classe. Au départ, cela a causé le même problème que le message d'origine lorsque j'ai utilisé le type de classe spécifique. Suite à cette réponse, j'ai changé pour utiliser le type d'interface avec différents @Qualifier("myServiceA")et @Qualifier("myServiceB"), et le problème a été résolu. Merci!
xialin
27

J'ai eu cela parce que mes tests n'étaient pas dans le même package que mes composants. (J'avais renommé mon package de composants, mais pas mon package de test.) Et j'utilisais @ComponentScandans ma @Configurationclasse de test , donc mes tests ne trouvaient pas les composants sur lesquels ils s'appuyaient.

Donc, revérifiez cela si vous obtenez cette erreur.

amarré
la source
2
Cela a fonctionné pour moi. Mes tests ont échoué lorsque j'ai refactoré le code pour passer à un nouveau nom de package car j'utilisais l'ancien nom de package dans @ComponentScan.
Vijay Vepakomma
1
Comment utiliser la @Configurationclasse de src/maindedans src/test?
Alex78191
10

Le fait est que le contexte d'application et le contexte d'application Web sont enregistrés dans WebApplicationContext lors du démarrage du serveur. Lorsque vous exécutez le test, vous devez indiquer explicitement les contextes à charger.

Essaye ça:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml", "/mvc-dispatcher-servlet.xml"})
emd
la source
1
Comment faire si j'utilise Spring Boot?
Alex78191
J'ai oublié de configurer l'analyse des composants pour les dépendances maven et j'ai du mal avec cela une fois par an.
b15
Si vous parlez de l'application elle-même et non des tests d'intégration, pour Spring Boot, vous pouvez le faire comme ceci: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15
5

J'ai passé beaucoup de temps avec ça! Ma faute! Plus tard, j'ai trouvé que la classe sur laquelle j'ai déclaré l'annotation Serviceou Componentétait de type abstract. Avait activé les journaux de débogage sur Springframework mais aucun indice n'a été reçu. Veuillez vérifier si la classe est de type abstrait. Si alors, la règle de base appliquée, ne peut pas instancier une classe abstraite.

James Jithin
la source
1
Vous m'avez sauvé la journée monsieur, c'est si difficile à détecter!
Japheth Ongeri - inkalimeva
3

Pouvez-vous essayer d'annoter uniquement votre implémentation concrète avec @Component? Peut-être que la réponse suivante pourrait vous aider. C'est un peu un problème similaire. Je mets généralement des annotations Spring dans les classes d'implémentation.

https://stackoverflow.com/a/10322456/2619091

yamilmedina
la source
3

J'étais confronté au même problème lors du câblage automatique de la classe à partir de l'un de mes fichiers jar. J'ai résolu le problème en utilisant l'annotation @Lazy:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;

Ved Singh
la source
2

La bonne manière doit être d'autowire AbstractManager, comme Max l'a suggéré, mais cela devrait également fonctionner correctement.

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

et

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

Je suis tombé dessus récemment, et il s'est avéré que j'ai importé la mauvaise annotation dans ma classe de service. Netbeans a une option pour masquer les déclarations d'importation, c'est pourquoi je ne l'ai pas vu depuis un certain temps.

J'ai utilisé à la @org.jvnet.hk2.annotations.Serviceplace de @org.springframework.stereotype.Service.

kazmer
la source
1
  • Une des raisons pour lesquelles BeanB peut ne pas exister dans le contexte
  • Une autre cause d'exception est l'existence de deux haricots
  • Ou les définitions dans le bean de contexte qui n'est pas défini sont demandées par leur nom dans le contexte Spring

voir plus cette url:

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

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

le même problème est arrivé, je l'ai résolu en gardant les annotations intactes et dans le servlet du répartiteur :: en gardant le scan du paquet de base car com.*.cela fonctionnait pour moi.

Ramanpreet Singh
la source
1

Cela peut vous aider:

J'ai la même exception dans mon projet. Après une recherche, j'ai trouvé qu'il me manquait l'annotation @Service pour la classe où j'implémente l'interface que je veux @Autowired.

Dans votre code, vous pouvez ajouter l'annotation @Service à la classe MailManager.

@Transactional
@Service
public class MailManager extends AbstractManager implements IMailManager {
Akshay Pethani
la source
L' @Serviceannotation contient @Component. Avoir les deux est redondant.
AnthonyW
1

Au lieu de @Autowire MailManager mailManager, vous pouvez vous moquer du bean comme indiqué ci-dessous:

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

::
::

@MockBean MailManager mailManager;

En outre, vous pouvez configurer @MockBean MailManager mailManager;séparément dans la @SpringBootConfigurationclasse et initialiser comme ci-dessous:

@Autowire MailManager mailManager
Barani r
la source
1

J'ai rencontré le même problème dans mon application de démarrage de printemps même si les analyses spécifiques de mon package étaient activées comme

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

Mais, le problème a été résolu en fournissant @ComponentScan({"com.*"})dans ma classe Application.

Rajish Nair
la source
0

Je suppose que c'est ici

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

toutes les annotations sont d'abord désactivées par use-default-filters = "false", puis seule l'annotation @Controller est activée. Ainsi, votre annotation @Component n'est pas activée.

LoBo
la source
0

Si vous testez votre contrôleur. N'oubliez pas d'utiliser @WebAppConfiguration sur votre classe de test.

Joao Luiz Cadore
la source
0

Cela s'est produit parce que j'ai ajouté une dépendance auto-câblée à ma classe de service, mais j'ai oublié de l'ajouter aux simulacres injectés dans mon test d'unité de service.

L'exception de test unitaire semblait signaler un problème dans la classe de service alors que le problème était en fait dans le test unitaire. Rétrospectivement, le message d'erreur m'a dit exactement quel était le problème.

Curtis Yallop
la source