@Autowosystem - Không tìm thấy loại bean đủ tiêu chuẩn nào cho sự phụ thuộc


89

Tôi đã bắt đầu dự án của mình bằng cách tạo các thực thể, dịch vụ và thử nghiệm JUnit cho các dịch vụ sử dụng Spring và Hibernate. Tất cả điều này hoạt động tuyệt vời. Sau đó, tôi đã thêm spring-mvc để tạo ứng dụng web này bằng nhiều hướng dẫn từng bước khác nhau, nhưng khi tôi cố gắng tạo Bộ điều khiển với chú thích @Autowosystem, tôi gặp lỗi từ Glassfish trong quá trình triển khai. Tôi đoán rằng vì lý do nào đó mà Spring không thấy các dịch vụ của tôi, nhưng sau nhiều lần thử tôi vẫn không xử lý được.

Kiểm tra các dịch vụ với

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

@Autowired
MailManager mailManager;

làm việc cẩn thận.

Bộ điều khiển không có @Autowosystem cũng vậy, tôi có thể mở dự án của mình trong trình duyệt web mà không gặp sự cố.

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

}

Lỗi:

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

Xin lỗi vì rất nhiều mã, nhưng tôi không biết điều gì có thể gây ra lỗi đó nữa.

Thêm

Tôi đã tạo giao diện:

@Component
public interface IMailManager {

bổ sung nông cụ:

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

và tự động thay đổi:

@Autowired
public IMailManager mailManager;

Nhưng nó vẫn phát ra lỗi (cũng như khi tôi đã thử với @Qualifier)

Trường ..Could not autowire: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

Tôi cũng đã thử với các kết hợp khác nhau của @Component và @Transactional.

Tôi có nên đưa bean.xml vào web.xml bằng cách nào đó không?


Bạn đang tải bean.xml như thế nào?
Michael Wiles

bây giờ làm thế nào về để lại chỉ một trong số MailManagerInterfaceIMailManager? :)
Patison

Xin lỗi, tôi đã dán mã sai. Trong chương trình của tôi có IMailManagerở khắp mọi nơi.
Radzikowski

ah, chính xác .. thêm <import resource="classpath:/beans.xml"/>vàomvc-dispatcher-servlet.xml
Patison

Nhân tiện, bạn đã thử quyết định @emd chưa?
Patison

Câu trả lời:


81

Bạn nên giao diện autowire AbstractManagerthay vì lớp MailManager. Nếu bạn có các cách ứng xử khác nhau, AbstractManagerbạn có thể viết @Component("mailService")và sau đó @Autowired @Qualifier("mailService")kết hợp để tự động truyền tải lớp cụ thể.

Điều này là do Spring tạo và sử dụng các đối tượng proxy dựa trên các giao diện.


2
Cảm ơn bạn nhưng nó vẫn không hoạt động (cùng một lỗi). Tôi đã thêm các thay đổi trong bài đăng. Có thể tôi không bao gồm / tìm kiếm thứ gì đó trong dự án của mình một cách hợp lý?
Radzikowski

Tôi tự hỏi liệu có cách nào để làm điều gì đó tương tự @Autowired AbstractManager[] abstractManagerscó chứa tất cả các triển khai của nó không.
WoLfPwNeR

@WoLfPwNeR Nó sẽ hoạt động chính xác như bạn đã viết. Xem liên kết
Patison

Tại sao không MailManager?
Alex78191

Tôi có hai @Servicelớp triển khai cùng một giao diện. Cả hai đều @Autowiredhọc lớp khác. Ban đầu, nó gây ra sự cố tương tự như bài viết gốc khi tôi sử dụng loại lớp cụ thể. Sau câu trả lời này, tôi đã thay đổi sang sử dụng loại Giao diện với @Qualifier("myServiceA")@Qualifier("myServiceB")và sự cố đã được giải quyết. Cảm ơn!
xialin

27

Tôi đã xảy ra điều này bởi vì các bài kiểm tra của tôi không nằm trong cùng một gói với các thành phần của tôi. (Tôi đã đổi tên gói thành phần của mình, nhưng không phải gói thử nghiệm của tôi.) Và tôi đang sử dụng@ComponentScan trong @Configurationlớp thử nghiệm của mình , vì vậy các bài kiểm tra của tôi không tìm thấy các thành phần mà chúng dựa vào.

Vì vậy, hãy kiểm tra kỹ xem nếu bạn gặp lỗi này.


2
Điều này đã làm việc cho tôi. Các thử nghiệm của tôi không thành công khi tôi cấu trúc lại mã để chuyển sang tên gói mới vì tôi đang sử dụng tên gói cũ trong @ComponentScan.
Vijay Vepakomma

1
Làm thế nào để sử dụng @Configurationlớp từ src/maintrong src/test?
Alex78191

10

Vấn đề là cả ngữ cảnh ứng dụng và ngữ cảnh ứng dụng web đều được đăng ký trong WebApplicationContext khi khởi động máy chủ. Khi bạn chạy thử nghiệm, bạn phải cho biết rõ ràng ngữ cảnh nào cần tải.

Thử đi:

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

1
Làm thế nào để làm điều đó nếu bạn đang sử dụng Spring Boot?
Alex78191

Tôi quên việc định cấu hình quét thành phần cho các phụ thuộc maven và vật lộn với điều này như vậy mỗi năm một lần.
b15

Nếu bạn đang nói về bản thân ứng dụng chứ không phải các bài kiểm tra tích hợp, đối với Spring boot, bạn có thể làm như thế này: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15

5

Tôi đã dành nhiều thời gian cho việc này! Lỗi của tôi! Sau đó nhận thấy rằng lớp mà tôi đã khai báo chú thích Servicehoặc Componentthuộc loại trừu tượng. Đã bật nhật ký gỡ lỗi trên Springframework nhưng không nhận được gợi ý nào. Vui lòng kiểm tra xem lớp nếu thuộc loại trừu tượng. Nếu sau đó, quy tắc cơ bản được áp dụng, không thể khởi tạo một lớp trừu tượng.


1
Bạn đã cứu ngày của tôi, thưa ông, điều này rất khó phát hiện!
Gia-phết Ongeri - inkalimeva


3

Tôi đã gặp phải vấn đề tương tự khi tự động nối dây lớp từ một trong các tệp jar của tôi. Tôi đã khắc phục sự cố bằng cách sử dụng chú thích @Lazy:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;


2

Cách đúng sẽ là autowire AbstractManager, như Max đã đề xuất, nhưng điều này cũng sẽ hoạt động tốt.

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

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

2

Gần đây tôi đã truy cập vào điều này và hóa ra, tôi đã nhập sai chú thích trong lớp dịch vụ của mình. Netbeans có một tùy chọn để ẩn các câu lệnh nhập, đó là lý do tại sao tôi không thấy nó trong một thời gian.

Tôi đã sử dụng @org.jvnet.hk2.annotations.Servicethay vì @org.springframework.stereotype.Service.


1
  • Một lý do khiến BeanB có thể không tồn tại trong ngữ cảnh
  • Một nguyên nhân khác cho ngoại lệ là sự tồn tại của hai hạt đậu
  • Hoặc các định nghĩa trong bean ngữ cảnh chưa được xác định được yêu cầu bằng tên từ ngữ cảnh Spring

xem thêm url này:

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


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

cùng một vấn đề đã đến, tôi đã giải quyết nó bằng cách giữ nguyên các chú thích và trong servlet điều phối viên :: giữ quét gói cơ sở vì com.*.điều này làm việc cho tôi.


1

Điều này có thể giúp bạn:

Tôi có cùng một ngoại lệ trong dự án của mình. Sau khi tìm kiếm trong khi tôi phát hiện ra rằng tôi thiếu chú thích @Service cho lớp mà tôi đang triển khai giao diện mà tôi muốn @Autowosystem.

Trong mã của mình, bạn có thể thêm chú thích @Service vào lớp MailManager.

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

Các @Servicechú thích chứa @Component. Có cả hai là thừa.
AnthonyW

1

Thay vì @Autowire MailManager mailManager, bạn có thể giả lập bean như dưới đây:

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

::
::

@MockBean MailManager mailManager;

Ngoài ra, bạn có thể cấu hình @MockBean MailManager mailManager;riêng trong @SpringBootConfigurationlớp và khởi tạo như sau:

@Autowire MailManager mailManager

1

Đối mặt với vấn đề tương tự trong ứng dụng khởi động mùa xuân của tôi mặc dù tôi đã bật tính năng quét gói cụ thể như

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

Tuy nhiên, vấn đề đã được giải quyết bằng cách cung cấp @ComponentScan({"com.*"})trong lớp Ứng dụng của tôi.


0

Tôi đoán là ở đây

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

đầu tiên tất cả các chú thích bị vô hiệu hóa bởi use-default-filter = "false" và sau đó chỉ bật chú thích @Controller. Do đó, chú thích @Component của bạn không được bật.


0

Nếu bạn đang kiểm tra bộ điều khiển của mình. Đừng quên sử dụng @WebAppConfiguration trên lớp thử nghiệm của bạn.


0

Tôi đã xảy ra điều này bởi vì tôi đã thêm phụ thuộc tự động mong muốn vào lớp dịch vụ của mình nhưng lại quên thêm nó vào các mocks được đưa vào trong thử nghiệm đơn vị dịch vụ của mình.

Ngoại lệ kiểm tra đơn vị xuất hiện để báo cáo sự cố trong lớp dịch vụ khi sự cố thực sự nằm trong thử nghiệm đơn vị. Khi nhìn lại, thông báo lỗi cho tôi biết chính xác vấn đề là gì.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.