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