@Autowired - Tidak ada jenis kacang yang memenuhi syarat yang ditemukan untuk ketergantungan

90

Saya telah memulai proyek saya dengan membuat entitas, layanan, dan pengujian JUnit untuk layanan menggunakan Spring dan Hibernate. Semua ini bekerja dengan baik. Kemudian saya telah menambahkan spring-mvc untuk membuat aplikasi web ini menggunakan banyak tutorial langkah demi langkah yang berbeda, tetapi ketika saya mencoba membuat Pengontrol dengan anotasi @Autowired, saya mendapatkan kesalahan dari Glassfish selama penerapan. Saya rasa untuk beberapa alasan Spring tidak melihat layanan saya, tetapi setelah banyak upaya saya masih tidak bisa mengatasinya.

Tes untuk layanan dengan

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

dan

@Autowired
MailManager mailManager;

bekerja dengan baik.

Pengontrol tanpa @Autowired juga, saya dapat membuka proyek saya di browser web tanpa masalah.

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

}

Kesalahan:

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

Maaf untuk banyak kode, tapi saya tidak tahu apa yang bisa menyebabkan kesalahan itu lagi.

Ditambahkan

Saya telah membuat antarmuka:

@Component
public interface IMailManager {

alat tambahan:

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

dan mengubah autowired:

@Autowired
public IMailManager mailManager;

Tapi masih ada kesalahan (juga ketika saya mencoba dengan @Qualifier)

..Tidak bisa autowire field: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

Saya sudah mencoba dengan kombinasi yang berbeda dari @Component dan @Transactional juga.

Bukankah saya harus menyertakan beans.xml di web.xml entah bagaimana?

Radzikowski
sumber
Bagaimana Anda memuat beans.xml?
Michael Wiles
sekarang bagaimana meninggalkan hanya satu dari MailManagerInterfacedan IMailManager? :)
Patison
Maaf, saya salah menempel kode. Dalam program saya ada IMailManagerdimana - mana.
Radzikowski
ah, tepatnya .. tambahkan <import resource="classpath:/beans.xml"/>kemvc-dispatcher-servlet.xml
Patison
Ngomong-ngomong, apakah Anda sudah mencoba keputusan @emd?
Patison

Jawaban:

81

Anda harus memasang antarmuka otomatis, AbstractManagerbukan kelas MailManager. Jika Anda memiliki implementasi yang berbeda AbstractManagerAnda dapat menulis @Component("mailService")dan kemudian @Autowired @Qualifier("mailService")menggabungkan ke autowire kelas tertentu.

Hal ini disebabkan oleh fakta bahwa Spring membuat dan menggunakan objek proxy berdasarkan antarmuka.

Patison
sumber
2
Terima kasih tetapi masih tidak berhasil (kesalahan yang sama). Saya menambahkan perubahan di postingan. Mungkin saya tidak menyertakan / mencari sesuatu dalam proyek saya dengan benar?
Radzikowski
Saya bertanya-tanya apakah ada cara untuk melakukan sesuatu seperti @Autowired AbstractManager[] abstractManagersitu yang berisi semua implementasinya.
WoLfPwNeR
@WoLfPwNeR Ini harus bekerja persis seperti yang Anda tulis. Lihat tautan
Patison
Mengapa tidak MailManager?
Alex78191
Saya memiliki dua @Servicekelas yang menerapkan antarmuka yang sama. Keduanya berada @Autowireddi kelas lain. Awalnya itu menyebabkan masalah yang sama seperti postingan asli ketika saya menggunakan tipe kelas tertentu. Mengikuti jawaban ini, saya mengubah menggunakan jenis Antarmuka dengan @Qualifier("myServiceA")dan @Qualifier("myServiceB"), dan masalah teratasi. Terima kasih!
xialin
27

Saya mengalami ini karena pengujian saya tidak dalam paket yang sama dengan komponen saya. (Saya telah mengganti nama paket komponen saya, tetapi bukan paket pengujian saya.) Dan saya menggunakan @ComponentScandi @Configurationkelas pengujian saya , jadi pengujian saya tidak menemukan komponen yang mereka andalkan.

Jadi, periksa kembali jika Anda mendapatkan kesalahan ini.

ditambatkan
sumber
2
Ini berhasil untuk saya. Pengujian saya gagal ketika saya memfaktorkan ulang kode untuk pindah ke nama paket baru karena saya menggunakan nama paket lama di @ComponentScan.
Vijay Vepakomma
1
Bagaimana cara menggunakan @Configurationkelas dari src/maindalam src/test?
Alex78191
10

Masalahnya adalah bahwa konteks aplikasi dan konteks aplikasi web terdaftar di WebApplicationContext selama startup server. Saat Anda menjalankan pengujian, Anda harus secara eksplisit memberi tahu konteks mana yang akan dimuat.

Coba ini:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml", "/mvc-dispatcher-servlet.xml"})
emd
sumber
1
Bagaimana cara melakukannya jika saya menggunakan Spring Boot?
Alex78191
Saya lupa tentang mengonfigurasi pemindaian komponen untuk dependensi maven dan berjuang dengan ini seperti setahun sekali.
b15
Jika Anda berbicara tentang aplikasi itu sendiri dan bukan tes integrasi, untuk Spring boot Anda dapat melakukannya seperti ini: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15
5

Menghabiskan banyak waktu saya dengan ini! Salahku! Kemudian menemukan bahwa kelas tempat saya mendeklarasikan anotasi Serviceatau Componentbertipe abstrak. Telah mengaktifkan log debug di Springframework tetapi tidak ada petunjuk yang diterima. Silakan periksa apakah kelasnya berjenis abstrak. Jika kemudian, aturan dasar yang diterapkan, tidak dapat membuat instance kelas abstrak.

James Jithin
sumber
1
Anda menyelamatkan hari saya Pak, ini sangat sulit untuk dideteksi!
Japheth Ongeri - inkalimeva
4

Saya menghadapi masalah yang sama saat memasang kabel otomatis kelas dari salah satu file jar saya. Saya memperbaiki masalah ini dengan menggunakan anotasi @Lazy:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;

Ved Singh
sumber
3

Dapatkah Anda mencoba memberi anotasi hanya pada implementasi konkret Anda @Component? Mungkin jawaban berikut bisa membantu. Ini masalah yang serupa. Saya biasanya meletakkan anotasi Spring di kelas implementasi.

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

yamilmedina
sumber
2

Cara yang benar adalah dengan autowire AbstractManager, seperti yang disarankan Max, tetapi ini akan bekerja dengan baik juga.

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

dan

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

Saya berlari ke ini baru-baru ini, dan ternyata, saya telah mengimpor anotasi yang salah di kelas layanan saya. Netbeans memiliki opsi untuk menyembunyikan pernyataan impor, itulah mengapa saya tidak melihatnya selama beberapa waktu.

Saya telah menggunakan, @org.jvnet.hk2.annotations.Servicebukan @org.springframework.stereotype.Service.

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

masalah yang sama tiba, saya menyelesaikannya dengan menjaga anotasi tetap utuh dan di dispatcher servlet :: menjaga pemindaian paket dasar karena com.*.ini berfungsi untuk saya.

Ramanpreet Singh
sumber
1

Ini dapat membantu Anda:

Saya memiliki pengecualian yang sama dalam proyek saya. Setelah mencari sementara saya menemukan bahwa saya kehilangan anotasi @Service ke kelas tempat saya mengimplementasikan antarmuka yang saya ingin @Autowired.

Dalam kode Anda, Anda dapat menambahkan anotasi @Service ke kelas MailManager.

@Transactional
@Service
public class MailManager extends AbstractManager implements IMailManager {
Akshay Pethani
sumber
The @Servicepenjelasan mengandung @Component. Memiliki keduanya itu mubazir.
AnthonyW
1

Daripada @Autowire MailManager mailManager, Anda dapat membuat tiruan kacang seperti yang diberikan di bawah ini:

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

::
::

@MockBean MailManager mailManager;

Selain itu, Anda dapat mengonfigurasi @MockBean MailManager mailManager;secara terpisah di @SpringBootConfigurationkelas dan menginisialisasi seperti di bawah ini:

@Autowire MailManager mailManager
Barani r
sumber
1

Menghadapi masalah yang sama di aplikasi boot musim semi saya meskipun saya mengaktifkan pemindaian khusus paket saya seperti

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

Namun, masalah tersebut diselesaikan dengan menyediakan @ComponentScan({"com.*"})di kelas Aplikasi saya.

Rajish Nair
sumber
0

Dugaan saya adalah di sini

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

semua anotasi pertama-tama dinonaktifkan oleh use-default-filters = "false" dan kemudian hanya anotasi @Controller yang diaktifkan. Karenanya, anotasi @Component Anda tidak diaktifkan.

LoBo
sumber
0

Jika Anda menguji pengontrol Anda. Jangan lupa untuk menggunakan @WebAppConfiguration di kelas pengujian Anda.

Joao Luiz Cadore
sumber
0

Saya mengalami ini terjadi karena saya menambahkan ketergantungan autowired ke kelas layanan saya tetapi lupa menambahkannya ke tiruan yang disuntikkan dalam pengujian unit layanan saya.

Pengecualian pengujian unit tampaknya melaporkan masalah di kelas layanan ketika masalah sebenarnya ada di pengujian unit. Dalam retrospeksi, pesan kesalahan memberitahu saya apa masalahnya.

Curtis Yallop
sumber
0

Solusi yang berhasil bagi saya adalah menambahkan semua kelas yang relevan ke @ContextConfiguration anotasi untuk kelas pengujian.

Kelas yang akan diuji MyClass.java, memiliki dua komponen yang dipasang secara otomatis: AutowireAdan AutowireB. Ini perbaikan saya.

@ContextConfiguration(classes = {MyClass.class, AutowireA.class, AutowireB.class})
public class MyClassTest {
...
}
iamfrank
sumber