@Autowired - Nenhum bean de qualificação do tipo encontrado para dependência


90

Comecei meu projeto criando entidades, serviços e testes JUnit para serviços usando Spring e Hibernate. Tudo isso funciona muito bem. Em seguida, adicionei spring-mvc para fazer este aplicativo da web usando muitos tutoriais passo a passo diferentes, mas quando estou tentando fazer Controller com a anotação @Autowired, recebo erros do Glassfish durante a implantação. Acho que por algum motivo o Spring não vê meus serviços, mas depois de muitas tentativas ainda não consigo lidar com isso.

Testes de serviços com

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

e

@Autowired
MailManager mailManager;

funciona corretamente.

Controladores sem @Autowired também, posso abrir meu projeto no navegador da web sem 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";
    }

}

Erro:

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

Desculpe por muito código, mas não sei mais o que pode causar esse erro.

Adicionado

Eu criei a interface:

@Component
public interface IMailManager {

implementos adicionados:

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

e mudou autowired:

@Autowired
public IMailManager mailManager;

Mas ainda gera erros (também quando tentei com @Qualifier)

..Não foi possível fazer o autowire: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

Eu tentei com diferentes combinações de @Component e @Transactional também.

Não devo incluir beans.xml em web.xml de alguma forma?


Como você está carregando o beans.xml?
— Michael Wiles

agora que tal deixar apenas um de MailManagerInterfacee IMailManager? :)
— Patison

Desculpe, colei mal o código. No meu programa existe em IMailManagertoda parte.
— Radzikowski

ah, exatamente .. adicionar <import resource="classpath:/beans.xml"/>amvc-dispatcher-servlet.xml
— Patison

A propósito, você tentou a decisão @emd?
— Patison

Respostas:


81

Você deve fazer o autowire da interface em AbstractManagervez da classe MailManager. Se você tiver diferentes implementações de, AbstractManagervocê pode escrever @Component("mailService")e, em seguida, @Autowired @Qualifier("mailService")combiná-las para conectar automaticamente uma classe específica.

Isso se deve ao fato de que o Spring cria e usa objetos proxy com base nas interfaces.


2
Obrigado, mas ainda não funciona (mesmo erro). Eu adicionei mudanças na postagem. Talvez eu não inclua / pesquise algo em meu projeto corretamente?
— Radzikowski

Estou me perguntando se existe uma maneira de fazer algo assim @Autowired AbstractManager[] abstractManagersque contenha todas as suas implementações.
— WoLfPwNeR

@WoLfPwNeR Deve funcionar exatamente como você escreveu. Ver link
— Patison

Porque não MailManager?
— Alex78191

Tenho duas @Serviceclasses implementando a mesma interface. Ambos estão @Autowiredem outra classe. Inicialmente, isso causou o mesmo problema da postagem original, quando usei o tipo de classe específico. Seguindo esta resposta, mudei para usar o tipo de Interface com diferente @Qualifier("myServiceA")e @Qualifier("myServiceB"), e o problema foi resolvido. Obrigado!
— xialin

27

Eu fiz isso acontecer porque meus testes não estavam no mesmo pacote que meus componentes. (Eu havia renomeado meu pacote de componentes, mas não meu pacote de teste.) E eu estava usando @ComponentScanem minha @Configurationclasse de teste , então meus testes não estavam encontrando os componentes nos quais confiavam.

Portanto, verifique se você receber esse erro.


2
Isso funcionou para mim. Meus testes falharam quando refatorou o código para mover para um novo nome de pacote porque estava usando o nome de pacote antigo em @ComponentScan.
— Vijay Vepakomma

1
Como usar a @Configurationclasse de src/mainem src/test?
— Alex78191

10

O fato é que tanto o contexto do aplicativo quanto o contexto do aplicativo da web são registrados no WebApplicationContext durante a inicialização do servidor. Ao executar o teste, você deve informar explicitamente quais contextos carregar.

Experimente isto:

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

1
Como fazer se estou usando Spring Boot?
— Alex78191

Esqueço-me de configurar a varredura de componente para dependências do maven e luto com isso uma vez por ano.
— b15,

Se você está falando sobre o aplicativo em si e não sobre os testes de integração, para o Spring boot, você pode fazer assim: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
— b15

5

Passei muito do meu tempo com isso! Foi mal! Posteriormente descobri que a classe na qual declarei a anotação Serviceou Componentera do tipo abstrato. Habilitou logs de depuração no Springframework, mas nenhuma dica foi recebida. Verifique se a classe é do tipo abstrato. Se então, a regra básica aplicada, não pode instanciar uma classe abstrata.


1
Você salvou meu dia, senhor, isso é tão difícil de detectar!
— Japheth Ongeri - inkalimeva

4

Eu estava enfrentando o mesmo problema ao fazer a fiação automática da classe de um de meus arquivos jar. Corrigi o problema usando a anotação @Lazy:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;



2

A maneira correta é autowire AbstractManager, como Max sugeriu, mas isso deve funcionar bem também.

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

e

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

2

Corri para isso recentemente e, como descobri, importei a anotação errada em minha classe de serviço. O Netbeans tem a opção de ocultar as declarações de importação, por isso não o via há algum tempo.

Eu usei em @org.jvnet.hk2.annotations.Servicevez de @org.springframework.stereotype.Service.



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

mesmo problema chegou, eu resolvi mantendo as anotações intactas e no servlet do despachante : mantendo a varredura do pacote básico, pois com.*.isso funcionou para mim.


1

Isso pode ajudá-lo a:

Eu tenho a mesma exceção em meu projeto. Depois de pesquisar enquanto descobri que estava faltando a anotação @Service para a classe onde estou implementando a interface que desejo @Autowired.

Em seu código, você pode adicionar a anotação @Service à classe MailManager.

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

A @Serviceanotação contém @Component. Ter ambos é redundante.
— AnthonyW

1

Em vez de @Autowire MailManager mailManager, você pode simular o bean conforme mostrado abaixo:

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

::
::

@MockBean MailManager mailManager;

Além disso, você pode configurar @MockBean MailManager mailManager;separadamente na @SpringBootConfigurationclasse e inicializar como abaixo:

@Autowire MailManager mailManager

1

Enfrentei o mesmo problema em meu aplicativo de inicialização de primavera, embora eu tivesse minhas varreduras específicas de pacote habilitadas, como

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

Mas, o problema foi resolvido fornecendo @ComponentScan({"com.*"})em minha classe de aplicativo.


0

Meu palpite é 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 as anotações são primeiro desabilitadas por use-default-filters = "false" e então apenas a anotação @Controller habilitada. Portanto, sua anotação @Component não está habilitada.


0

Se você estiver testando seu controlador. Não se esqueça de usar @WebAppConfiguration em sua classe de teste.


0

Fiz isso acontecer porque adicionei uma dependência autowired à minha classe de serviço, mas esqueci de adicioná-la às simulações injetadas em meu teste de unidade de serviço.

A exceção do teste de unidade parecia relatar um problema na classe de serviço quando o problema estava na verdade no teste de unidade. Em retrospecto, a mensagem de erro me disse exatamente qual era o problema.


0

A solução que funcionou para mim foi adicionar todas as classes relevantes ao @ContextConfiguration anotação para a classe de teste.

A classe a ser testada MyClass.java,, tinha dois componentes autowired: AutowireAe AutowireB. Aqui está minha correção.

@ContextConfiguration(classes = {MyClass.class, AutowireA.class, AutowireB.class})
public class MyClassTest {
...
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.