@Autowired - Bağımlılık için uygun bir fasulye türü bulunamadı


90

Spring ve Hibernate kullanan hizmetler için varlıklar, hizmetler ve JUnit testleri oluşturarak projeme başladım. Bütün bunlar harika çalışıyor. Ardından, bu web uygulamasını birçok farklı adım adım öğretici kullanarak yapmak için spring-mvc ekledim, ancak Controller'ı @Autowired ek açıklamasıyla yapmaya çalışırken, dağıtım sırasında Glassfish'ten hatalar alıyorum. Sanırım bir sebepten dolayı Spring benim hizmetlerimi görmüyor, ancak birçok denemeden sonra hala başa çıkamıyorum.

Hizmetlerle ilgili testler

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

ve

@Autowired
MailManager mailManager;

düzgün çalışır.

@Autowired olmayan kontrolörler de projemi web tarayıcısında sorunsuz bir şekilde açabilirim.

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

}

Hata:

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

Bir çok kod için özür dilerim ama artık bu hataya neyin sebep olabileceğini bilmiyorum.

Katma

Arayüzü oluşturdum:

@Component
public interface IMailManager {

eklenen aletler:

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

ve değiştirilen otomatik kablolama:

@Autowired
public IMailManager mailManager;

Ama yine de hatalar atıyor (ayrıca @Qualifier ile denediğimde)

..Alanı otomatik olarak bağlayamadı: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...

@Component ve @Transactional'ın farklı kombinasyonlarını da denedim.

Bean.xml'yi bir şekilde web.xml'ye eklemem gerekmez mi?


Bean.xml dosyasını nasıl yüklüyorsunuz?
Michael Wiles

Şimdi nasıl sadece birini terk etmek MailManagerInterfaceve IMailManager? :)
Patison

Üzgünüm, kodu kötü bir şekilde yapıştırdım. Benim programımda IMailManagerher yer var.
Radzikowski

ah aynen .. eklemek <import resource="classpath:/beans.xml"/>içinmvc-dispatcher-servlet.xml
Patison

Bu arada @emd kararını denedin mi?
Patison

Yanıtlar:


81

Arayüzü AbstractManagersınıf yerine otomatik olarak bağlamalısınız MailManager. Farklı uygulamalarınız AbstractManagervarsa, belirli bir sınıfı otomatik olarak bağlamak için yazabilir @Component("mailService")ve ardından @Autowired @Qualifier("mailService")kombinasyon yapabilirsiniz .

Bunun nedeni, Spring'in arayüzlere dayalı proxy nesneleri oluşturması ve kullanmasıdır.


2
Teşekkürler ama yine de çalışmıyor (aynı hata). Gönderiye değişiklikler ekledim. Belki projeme düzgün bir şekilde bir şey eklemiyorum / aramıyorum?
Radzikowski

@Autowired AbstractManager[] abstractManagersBütün uygulamalarını içeren böyle bir şey yapmanın bir yolu olup olmadığını merak ediyorum .
WoLfPwNeR

@WoLfPwNeR Tam olarak yazdığınız gibi çalışmalıdır. Bağlantıya
Patison

Neden olmasın MailManager?
Alex78191

@ServiceAynı arayüzü uygulayan iki sınıfım var . Her ikisi de @Autowiredbaşka bir sınıfta. Başlangıçta, belirli sınıf türünü kullandığımda orijinal gönderiyle aynı soruna neden oldu. Bu cevabın ardından farklı @Qualifier("myServiceA")ve ile Arayüz tipini kullanmaya başladım @Qualifier("myServiceB")ve sorun çözüldü. Teşekkürler!
xialin

27

Bunu yaptım çünkü testlerim bileşenlerimle aynı pakette değildi. (Bileşen paketimi yeniden adlandırmıştım, ancak test paketimi değiştirmemiştim.) Ve @ComponentScantest @Configurationsınıfımda kullanıyordum, bu nedenle testlerim, güvendikleri bileşenleri bulamıyordu.

Yani, bu hatayı alırsanız iki kez kontrol edin.


2
Bu benim için çalıştı. @ComponentScan'de eski paket adını kullandığım için kodu yeni bir paket adına taşımak için yeniden düzenlediğimde testlerim başarısız oldu.
Vijay Vepakomma

1
Nasıl kullanmak @Configurationgelen sınıf src/mainiçinde src/test?
Alex78191

10

Mesele şu ki, hem uygulama bağlamı hem de web uygulaması bağlamı, sunucu başlatılırken WebApplicationContext'e kaydedilir. Testi çalıştırdığınızda, hangi bağlamların yükleneceğini açıkça söylemelisiniz.

Bunu dene:

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

1
Spring Boot kullanıyorsam nasıl yapılır?
Alex78191

Bileşen taramasını maven bağımlılıkları için yapılandırmayı unutuyorum ve yılda bir kez olduğu gibi bununla mücadele ediyorum.
b15

Entegrasyon testlerinden değil de uygulamanın kendisinden bahsediyorsanız, Spring boot için bunu şu şekilde yapabilirsiniz: @SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
b15

5

Zamanımın çoğunu bununla geçirdim! Benim hatam! Daha sonra sınıf hangi ı şerh ilan bulundu Serviceveya Componenttip soyut oldu. Springframework üzerinde hata ayıklama günlükleri etkinleştirildi, ancak hiçbir ipucu alınmadı. Lütfen sınıfın soyut tip olup olmadığını kontrol edin. O zaman, temel kural uygulanırsa, soyut bir sınıfı başlatamaz.


1
Günümü kurtardınız efendim, bunu tespit etmek çok zor!
Japheth Ongeri - inkalimeva

4

Sınıfı jar dosyamdan birinden otomatik olarak bağlarken aynı sorunla karşılaşıyordum. @Lazy annotation kullanarak sorunu düzelttim:

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

    @Autowired
    @Lazy
    private IGalaxyCommand iGalaxyCommand;



2

Doğru yol, Max'in önerdiği gibi AbstractManager'ı otomatik olarak bağlamak olacaktır, ancak bu da iyi çalışmalıdır.

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

ve

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

2

Yakın zamanda buna rastladım ve ortaya çıktığı gibi, hizmet sınıfıma yanlış notu içe aktardım. Netbeans'in içe aktarma ifadelerini gizleme seçeneği var, bu yüzden onu bir süredir görmedim.

Onun @org.jvnet.hk2.annotations.Serviceyerine kullandım @org.springframework.stereotype.Service.



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

aynı sorun geldi, ek açıklamaları olduğu gibi bırakarak ve dağıtıcı servlet : com.*.benim için çalıştığı için temel paket taramasını tutarak çözdüm .


1

Bu size yardımcı olabilir:

Projemde de aynı istisnaya sahibim. Aradıktan sonra, @Autowired yapmak istediğim arabirimi uyguladığım sınıfa yönelik @Service ek açıklamasını kaçırdığımı buldum.

Kodunuzda @Service ek açıklamasını MailManager sınıfına ekleyebilirsiniz.

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

@ServiceEk açıklama içerir @Component. Her ikisine de sahip olmak gereksizdir.
AnthonyW

1

@Autowire MailManager mailManager yerine, aşağıdaki gibi bean ile alay edebilirsiniz:

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

::
::

@MockBean MailManager mailManager;

Ayrıca, sınıfta @MockBean MailManager mailManager;ayrı ayrı yapılandırabilir @SpringBootConfigurationve aşağıdaki gibi başlatabilirsiniz :

@Autowire MailManager mailManager

1

İlkbahar önyükleme uygulamamda aynı sorunla karşılaştım, pakete özel taramalarım gibi

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

Ancak, @ComponentScan({"com.*"})uygulama sınıfımda sağlanarak sorun çözüldü .


0

Benim tahminim burada

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

tüm ek açıklamalar önce use-default-filters = "false" tarafından devre dışı bırakılır ve ardından yalnızca @Controller ek açıklaması etkinleştirilir. Böylelikle, @Component notunuz etkinleştirilmez.


0

Denetleyicinizi test ediyorsanız. Test sınıfınızda @WebAppConfiguration kullanmayı unutmayın.


0

Bu, hizmet sınıfıma otomatik bağlantılı bir bağımlılık eklediğim, ancak bunu hizmet birimi testimde enjekte edilen taklitlere eklemeyi unuttuğum için oldu.

Birim testi istisnası, sorun aslında birim testindeyken hizmet sınıfında bir sorunu bildiriyor gibi göründü. Geriye dönüp bakıldığında, hata mesajı bana sorunun tam olarak ne olduğunu söyledi.


0

Benim için işe yarayan çözüm, ilgili tüm sınıfları @ContextConfigurationtest sınıfı için ek açıklamaya eklemekti .

Test edilecek sınıfın MyClass.javaiki otomatik bağlantılı bileşeni vardı: AutowireAve AutowireB. İşte düzeltmem.

@ContextConfiguration(classes = {MyClass.class, AutowireA.class, AutowireB.class})
public class MyClassTest {
...
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.