Rozpocząłem swój projekt od stworzenia encji, usług i testów JUnit dla usług wykorzystujących Spring i Hibernate. Wszystko to działa świetnie. Następnie dodałem spring-mvc, aby utworzyć tę aplikację internetową, korzystając z wielu różnych samouczków krok po kroku, ale kiedy próbuję utworzyć kontroler z adnotacją @Autowired, podczas wdrażania otrzymuję błędy od Glassfish. Myślę, że z jakiegoś powodu Spring nie widzi moich usług, ale po wielu próbach nadal nie mogę sobie z tym poradzić.
Testy usług z
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/beans.xml"})
i
@Autowired
MailManager mailManager;
działa poprawnie.
Kontrolery bez @Autowired też, mogę bez problemu otworzyć swój projekt w przeglądarce internetowej.
/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";
}
}
Błąd:
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)}
Przepraszam za dużo kodu, ale nie wiem już, co może powodować ten błąd.
Dodany
Stworzyłem interfejs:
@Component
public interface IMailManager {
dodane narzędzia:
@Component
@Transactional
public class MailManager extends AbstractManager implements IMailManager {
i zmieniony autowired:
@Autowired
public IMailManager mailManager;
Ale nadal generuje błędy (również gdy próbowałem z @Qualifier)
..Could not autowire field: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager ...
Próbowałem też z różnymi kombinacjami @Component i @Transactional.
Czy nie powinienem jakoś umieszczać beans.xml w pliku web.xml?
źródło
MailManagerInterface
iIMailManager
? :)IMailManager
wszędzie.<import resource="classpath:/beans.xml"/>
domvc-dispatcher-servlet.xml
Odpowiedzi:
Powinieneś autowire interfejs
AbstractManager
zamiast classMailManager
. Jeśli masz różne implikacjeAbstractManager
, możesz napisać,@Component("mailService")
a następnie@Autowired @Qualifier("mailService")
połączyć, aby autowire konkretną klasę.Wynika to z faktu, że Spring tworzy i wykorzystuje obiekty proxy w oparciu o interfejsy.
źródło
@Autowired AbstractManager[] abstractManagers
który zawiera wszystkie jego implementacje.MailManager
?@Service
klasy implementujące ten sam interfejs. Obie są@Autowired
w innej klasie. Początkowo powodowało to ten sam problem, co oryginalny post, gdy użyłem określonego typu zajęć. Po tej odpowiedzi zmieniłem typ interfejsu na inny@Qualifier("myServiceA")
i@Qualifier("myServiceB")
, a problem został rozwiązany. Dzięki!Tak się stało, ponieważ moje testy nie były w tym samym opakowaniu, co moje komponenty. (Zmieniłem nazwę mojego pakietu komponentów, ale nie mojego pakietu testowego). Używałem go
@ComponentScan
w@Configuration
klasie testowej , więc moje testy nie znajdowały komponentów, na których polegały.Więc sprawdź to dokładnie, jeśli pojawi się ten błąd.
źródło
@Configuration
z klasysrc/main
wsrc/test
?Chodzi o to, że zarówno kontekst aplikacji, jak i kontekst aplikacji internetowej są rejestrowane w WebApplicationContext podczas uruchamiania serwera. Po uruchomieniu testu musisz wyraźnie określić, które konteksty mają zostać załadowane.
Spróbuj tego:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:/beans.xml", "/mvc-dispatcher-servlet.xml"})
źródło
@SpringBootApplication(scanBasePackages = { "com.package.one", "com.package.two" })
Spędziłem z tym dużo czasu! Mój błąd! Później stwierdziłem, że klasa, na której zadeklarowałem adnotację
Service
lubComponent
była typu abstrakcyjnego. Włączono dzienniki debugowania na Springframework, ale nie otrzymano żadnej wskazówki. Sprawdź, czy klasa jest typu abstrakcyjnego. Jeśli tak, zastosowana podstawowa reguła nie może utworzyć instancji klasy abstrakcyjnej.źródło
Czy możesz spróbować dodać przypisy tylko do konkretnej implementacji
@Component
? Może poniższa odpowiedź mogłaby pomóc. To jest podobny problem. Adnotacje Spring zwykle umieszczam w klasach implementacji.https://stackoverflow.com/a/10322456/2619091
źródło
Miałem ten sam problem podczas automatycznego łączenia klasy z jednego z moich plików jar. Naprawiłem problem, używając adnotacji @Lazy:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @Autowired @Lazy private IGalaxyCommand iGalaxyCommand;
źródło
Poprawnym sposobem powinno być automatyczne podłączenie AbstractManagera, jak zasugerował Max, ale to też powinno działać dobrze.
@Autowired @Qualifier(value="mailService") public MailManager mailManager;
i
@Component("mailService") @Transactional public class MailManager extends AbstractManager { }
źródło
Niedawno wpadłem na to i jak się okazało, zaimportowałem niewłaściwą adnotację w mojej klasie usług. Netbeans ma możliwość ukrycia instrukcji importu, dlatego przez jakiś czas jej nie widziałem.
Użyłem
@org.jvnet.hk2.annotations.Service
zamiast@org.springframework.stereotype.Service
.źródło
zobacz więcej ten adres URL:
http://www.baeldung.com/spring-nosuchbeandefinitionexception
źródło
<context:component-scan base-package="com.*" />
Pojawił się ten sam problem, rozwiązałem go, utrzymując adnotacje w stanie nienaruszonym i w serwlecie dyspozytorskim : utrzymując skanowanie pakietu podstawowego, ponieważ
com.*.
działało to dla mnie.źródło
To może ci pomóc:
Mam ten sam wyjątek w moim projekcie. Po przeszukaniu stwierdziłem, że brakuje mi adnotacji @Service do klasy, w której implementuję interfejs, który chcę @Autowired.
W swoim kodzie możesz dodać adnotację @Service do klasy MailManager.
@Transactional @Service public class MailManager extends AbstractManager implements IMailManager {
źródło
@Service
Adnotacja zawiera@Component
. Posiadanie obu jest zbędne.Zamiast @Autowire MailManager mailManager, możesz kpić z fasoli, jak podano poniżej:
import org.springframework.boot.test.mock.mockito.MockBean; :: :: @MockBean MailManager mailManager;
Możesz także skonfigurować
@MockBean MailManager mailManager;
osobno w@SpringBootConfiguration
klasie i zainicjować jak poniżej:@Autowire MailManager mailManager
źródło
Napotkałem ten sam problem w mojej aplikacji do rozruchu wiosennego, mimo że miałem włączone skanowanie specyficzne dla mojego pakietu, np
@SpringBootApplication(scanBasePackages={"com.*"})
Ale problem został rozwiązany przez dostarczenie
@ComponentScan({"com.*"})
w mojej klasie Application.źródło
Domyślam się, że tutaj
<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>
wszystkie adnotacje są najpierw wyłączane przez use-default-filters = "false", a następnie włączane są tylko adnotacje @Controller. Dlatego Twoja adnotacja @Component nie jest włączona.
źródło
Jeśli testujesz swój kontroler. Nie zapomnij użyć @WebAppConfiguration w swojej klasie testowej.
źródło
Stało się tak, ponieważ dodałem autowired zależność do mojej klasy usług, ale zapomniałem dodać ją do wstrzykniętych makiet w moim teście jednostki usług.
Wydaje się, że wyjątek testu jednostkowego zgłosił problem w klasie usługi, gdy problem faktycznie występował podczas testu jednostkowego. Z perspektywy czasu komunikat o błędzie powiedział mi dokładnie, na czym polega problem.
źródło