@Autowired - Не знайдено відповідного компонента типу для залежності


89

Я розпочав свій проект із створення сутностей, служб та тестів JUnit для служб, що використовують Spring та Hibernate. Все це чудово працює. Потім я додав spring-mvc, щоб зробити цей веб-додаток, використовуючи безліч різних покрокових підручників, але коли я намагаюся зробити Controller з @Autowired анотацією, я отримую помилки від Glassfish під час розгортання. Я думаю, що чомусь Spring не бачить моїх послуг, але після багатьох спроб я все ще не можу з цим впоратися.

Тести на послуги з

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

і

@Autowired
MailManager mailManager;

працює належним чином.

Контролери без @Autowired теж, я без проблем можу відкрити свій проект у веб-браузері.

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

}

Помилка:

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

Вибачте за багато коду, але я не знаю, що може спричинити цю помилку.

Додано

Я створив інтерфейс:

@Component
public interface IMailManager {

додані знаряддя:

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

і змінено автопровід:

@Autowired
public IMailManager mailManager;

Але все одно видає помилки (також коли я пробував із @Qualifier)

.. Не вдалося автоматично підключити поле: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

Я також пробував із різними комбінаціями @Component та @Transactional.

Чи не слід мені якось включати beans.xml до web.xml?


Як ви завантажуєте beans.xml?
Michael Wiles

а як тепер залишити лише одну з MailManagerInterfaceі IMailManager? :)
Patison

Вибачте, я погано вставив код. У моїй програмі є IMailManagerвсюди.
Радзіковський

ах, точно .. додати <import resource="classpath:/beans.xml"/>вmvc-dispatcher-servlet.xml
Patison

До речі, ви пробували рішення @emd?
Patison

Відповіді:


81

Вам слід автоматично підключати інтерфейс AbstractManagerзамість класу MailManager. Якщо у вас є різні реалізації, AbstractManagerви можете писати, @Component("mailService")а потім @Autowired @Qualifier("mailService")комбінувати для автопровідного класу.

Це пов'язано з тим, що Spring створює та використовує об'єкти-проксі на основі інтерфейсів.


2
Дякую, але це все одно не працює (та сама помилка). Я додав зміни до повідомлення. Можливо, я не включаю / шукаю щось у своєму проекті належним чином?
Радзіковський

Мені цікаво, чи є спосіб зробити щось подібне, @Autowired AbstractManager[] abstractManagersщо містить усі його реалізації.
WoLfPwNeR

@WoLfPwNeR Він повинен працювати точно так, як ви писали. Див. Посилання
Patison

Чому ні MailManager?
Alex78191

У мене є два @Serviceкласи, що реалізують один і той же інтерфейс. Обидва навчаються @Autowiredв іншому класі. Спочатку це викликало ту ж проблему, що і оригінальний пост, коли я використовував конкретний тип класу. Після цієї відповіді я змінив тип інтерфейсу з різними @Qualifier("myServiceA")і @Qualifier("myServiceB"), і проблема була вирішена. Дякую!
xialin

27

У мене це сталося, тому що мої тести не були в тому ж пакеті, що й мої компоненти. (Я перейменовував свій компонентний пакет, але не мій тестовий пакет.) І я використовував @ComponentScanу своєму тестовому @Configurationкласі, тому мої тести не знаходили компонентів, на які вони покладались.

Отже, ще раз перевірте, чи з’являється ця помилка.


2
Це спрацювало для мене. Мої тести не вдались, коли я переробив код на нове ім’я пакета, оскільки я використовував старе ім’я пакета в @ComponentScan.
Віджай Вепакомма

1
Як використовувати @Configurationклас з src/mainin src/test?
Alex78191

10

Річ у тому, що як контекст програми, так і контекст веб-програми реєструються в WebApplicationContext під час запуску сервера. Під час запуску тесту ви повинні чітко вказати, які контексти завантажувати.

Спробуйте це:

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

1
Як це зробити, якщо я використовую Spring Boot?
Alex78191,

Я забуваю про налаштування сканування компонентів на залежності maven і боюся з цим, як раз на рік.
b15

Якщо ви говорите про саму програму, а не про тести інтеграції, для завантаження Spring ви можете зробити це так: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15

5

Провів з цим велику частину свого часу! Моє ліжко! Пізніше виявив, що клас, в якому я оголосив анотацію Serviceабо Componentбув абстрактним типом. Увімкнув журнали налагодження на Springframework, але жодної підказки не отримано. Будь ласка, перевірте, чи є клас абстрактним. Якщо тоді, основне правило, яке застосовується, не може створити екземпляр абстрактного класу.


1
Ви врятували мій день, сер, це так важко виявити!
Japheth Ongeri - inkalimeva


3

Я зіткнувся з такою ж проблемою під час автоматичного підключення класу до одного з мого файлу jar. Я виправив проблему за допомогою анотації @Lazy:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;


2

Правильним способом буде автоматичне підключення AbstractManager, як запропонував Макс, але це також повинно працювати нормально.

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

і

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

2

Я нещодавно зіткнувся з цим, і, як виявилося, я імпортував неправильну анотацію у своєму класі обслуговування. Netbeans має можливість приховати оператори імпорту, тому я деякий час цього не бачив.

Я використовував @org.jvnet.hk2.annotations.Serviceзамість @org.springframework.stereotype.Service.


1
  • Одна з причин, чому BeanB може не існувати в контексті
  • Ще однією причиною винятку є існування двох бобів
  • Або визначення в контексті bean, який не визначений, запитується за назвою з контексту Spring

див. більше за цією URL-адресою:

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


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

прибула та сама проблема, я вирішив це, зберігаючи анотації цілими та в сервлеті диспетчера :: зберігаючи сканування базового пакету, оскільки com.*.це працювало для мене.


1

Це може допомогти вам:

У мене такий же виняток у моєму проекті. Після пошуку, поки я виявив, що мені не вистачає анотації @Service до класу, де я реалізую інтерфейс, який я хочу до @Autowired.

У своєму коді ви можете додати анотацію @Service до класу MailManager.

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

@ServiceАнотацій містить @Component. Наявність обох зайвих.
AnthonyW

1

Замість @Autowire MailManager mailManager ви можете знущатись над біном, як зазначено нижче:

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

::
::

@MockBean MailManager mailManager;

Крім того, ви можете налаштувати @MockBean MailManager mailManager;окремо в @SpringBootConfigurationкласі та ініціалізувати, як показано нижче:

@Autowire MailManager mailManager

1

Зіткнувся з тією ж проблемою в моєму весняному завантажувальному додатку, навіть незважаючи на те, що у мене було ввімкнено сканування певного пакета, наприклад

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

Але проблему було вирішено шляхом надання @ComponentScan({"com.*"})в моєму класі Application.


0

Я припускаю, що тут

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

усі анотації спочатку вимикаються за допомогою use-default-filters = "false", а потім увімкнено лише анотацію @Controller. Таким чином, ваша анотація @Component не ввімкнена.



0

У мене це сталося, тому що я додав автоматичну залежність до свого сервісного класу, але забув додати її до введених макетів у тесті мого сервісного блоку.

Здається, виняток модульного тесту повідомляє про проблему в класі обслуговування, коли проблема була насправді в модульному тестуванні. В ретроспективі повідомлення про помилку повідомило мені, в чому саме полягає проблема.


0

Рішення, яке працювало для мене, було додати всі відповідні класи до @ContextConfigurationанотації для тестуючого класу.

Клас для тестування MyClass.javaмав два автоматично підключені компоненти: AutowireAі AutowireB. Ось моє виправлення.

@ContextConfiguration(classes = {MyClass.class, AutowireA.class, AutowireB.class})
public class MyClassTest {
...
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.