I've started my project by creating entities, services and JUnit tests for services using Spring and Hibernate. All of this works great. Then I've added spring-mvc to make this web application using many different step-by-step tutorials, but when I'm trying to make Controller with @Autowired
annotation, I'm getting errors from Glassfish during deployment. I guess that for some reason Spring doesn't see my services, but after many attempts I still can't handle it.
Tests for services with
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:/beans.xml"})
and
@Autowired MailManager mailManager;
works properly.
Controllers without @Autowired
too, I can open my project in web browser without trouble.
/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"; } }
Error:
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)}
Sorry for a lot of code, but I don't know what can cause that error anymore.
Added
I've created the interface:
@Component public interface IMailManager {
added implements:
@Component @Transactional public class MailManager extends AbstractManager implements IMailManager {
and changed autowired:
@Autowired public IMailManager mailManager;
But it still throws errors (also when I've tried with @Qualifier
)
..Could not autowire field: public pl.com.radzikowski.webmail.service.IMailManager pl.com.radzikowski.webmail.controller.HomeController.mailManager...
I've tried with different combinations of @Component
and @Transactional
too.
Shouldn't I include beans.xml in web.xml somehow?
The error is “expected at least 1 bean which qualifies as autowire candidate.” The solution is to add the injection class in the ApplicationContext using annotation @Component. The exception “NoSuchBeanDefinitionException: No qualifying bean of type” is resolved if the annotation @Component is added in the Lion class.
Spring @Autowired annotation is used for automatic dependency injection. Spring framework is built on dependency injection and we inject the class dependencies through spring bean configuration file.
If you are using Spring XML configuration then you can exclude a bean from autowiring by setting the autowire-candidate attribute of the <bean/> element to false. That way container makes that specific bean definition unavailable to the autowiring infrastructure.
When @Autowired doesn't work. There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.
You should autowire interface AbstractManager
instead of class MailManager
. If you have different implemetations of AbstractManager
you can write @Component("mailService")
and then @Autowired @Qualifier("mailService")
combination to autowire specific class.
This is due to the fact that Spring creates and uses proxy objects based on the interfaces.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With