Spring web app - autowire - can not find bean to inject - java

I have a spring controller with an autowired object that Spring says it can't find, despite my seeing - in the log file - the bean/object for it being created in the root application context. It occurs during the deployment of the application (in Tomcat).
I tried adding #Qualifier to the #Autowired field but it didn't resolve the problem.
Controller:
package com.maha.testspring.endpoints.webrest.controllers;
import com.maha.testspring.services.TestSpringService;
#Controller
#RequestMapping("/testspring")
public class TestSpringController
{
#Autowired
#Qualifier("testSpringService")
private TestSpringService testSpringService;
...
}
war's testspring-endpoints-webrest-1.0-SNAPSHOT/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
war's testspring-endpoints-webrest-1.0-SNAPSHOT/WEB-INF/spring/servlet-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
...
<mvc:annotation-driven />
<context:annotation-config />
<context:spring-configured />
<context:component-scan base-package="com.maha.testspring.endpoints.webrest.controllers" />
</beans:beans>
war's testspring-endpoints-webrest-1.0-SNAPSHOT/WEB-INF/spring/root-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...
<bean class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>/applicationContext.testspring.services.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
Service implementation class: (in jar, testspring-services-impl-1.0-SNAPSHOT.jar - in the war's testspring-endpoints-webrest-1.0-SNAPSHOT\WEB-INF\lib folder)
package com.maha.testspring.services;
import org.springframework.stereotype.Service;
#Service("testSpringService")
public class TestSpringServiceImpl implements TestSpringService {
public void testIt() { System.out.println("..."); }
}
Service interface: (in jar, testspring-services-interfaces-1.0-SNAPSHOT.jar - in the war's testspring-endpoints-webrest-1.0-SNAPSHOT\WEB-INF\lib folder)
package com.maha.testspring.services;
public interface TestSpringService
{
public void testIt();
}
applicationContext.testspring.services.xml (in jar, testspring-services-impl-1.0-SNAPSHOT.jar - in the war's testspring-endpoints-webrest-1.0-SNAPSHOT\WEB-INF\lib folder)
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:spring-configured/>
<context:annotation-config />
<context:component-scan base-package="com.maha.testspring.services"/>
</beans>
Logging - shows TestSpringServiceImpl was processed for #Service (as a candidate component when injecting dependency later on)
annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: URL [jar:file:/C:/osd/Tomcat%208.0/webapps/testspringwebrest/WEB-INF/lib/testspring-services-impl-1.0-SNAPSHOT.jar!/com/maha/testspring/services/TestSpringServiceImpl.class]
support.ClassPathXmlApplicationContext - Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext#41e89deb: org.springframework.beans.factory.support.DefaultListableBeanFactory#7487b2bc
Logging shows creation of bean instance for this class:
support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'testSpringService'
support.DefaultListableBeanFactory - Creating instance of bean 'testSpringService'
support.DefaultListableBeanFactory - Eagerly caching bean 'testSpringService' to allow for resolving potential circular references
support.DefaultListableBeanFactory - Finished creating instance of bean 'testSpringService'
Error when trying to create the controller - can't find the bean to inject:
support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'testSpringController'
support.DefaultListableBeanFactory - Creating instance of bean 'testSpringController'
annotation.InjectionMetadata - Registered injected element on
class [com.maha.testspring.endpoints.webrest.controllers.TestSpringController]: AutowiredFieldElement for
private com.maha.testspring.services.TestSpringService com.maha.testspring.endpoints.webrest.controllers.TestSpringController.testSpringService
annotation.InjectionMetadata - Processing injected element of bean 'testSpringController':
AutowiredFieldElement for private
com.maha.testspring.services.TestSpringService
com.maha.testspring.endpoints.webrest.controllers.TestSpringController.testSpringService
support.XmlWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testSpringController':
Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.maha.testspring.services.TestSpringService com.maha.testspring.endpoints.webrest.controllers.TestSpringController.testSpringService;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[com.maha.testspring.services.TestSpringService] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.

I had a similar problem . We solved it by keeping the CASE same . In your example you used #Qualifier("testSpringService")
and your yout service public class TestSpringServiceImpl implements TestSpringService
TRY changing it to public class TestSpringServiceImpl implements testSpringService with a SMALL t in testSpringService.
If that dont solve your problem then try annotating the parent class (Remember that annotations are not inherited from parent class to the child and in your case you have annotated the child and not its parent ) like :
package com.maha.testspring.services;
#Service("testSpringService")
public interface TestSpringService
{
public void testIt();
}

Related

Spring MVC autowiring bean throws nestedexception

I have big problems with autowiring in Spring MVC 4 and I already spent many hours on it. Found many solutions but nothing helps.
I have Controller:
#Controller
public class PrintedBookController {
#Autowired
PrintedBookService pbookService; // interface
#RequestMapping(value = "/pbook", method = RequestMethod.GET)
public ModelAndView pbook() {
return new ModelAndView("pbook", "command", new PrintedBookDTO());
}
...
}
Also have:
PrintedBookService // this is interface
PrintedBookServiceImpl // this is implementation of PrintedBookService
in printedbookserviceimpl is:
#Service
#Transactional
public class PrintedBookServiceImpl implements PrintedBookService {
#Autowired
private PrintedBookDAO pbookDao;
#Autowired
private BookDAO bookDao;
#Autowired
private LoanDAO loanDao;
public void setPrintedBookDao(PrintedBookDAO pbookDao) {
this.pbookDao = pbookDao;
}
....
}
the daos in PrintedBookServiceImpl are interfaces
The dao implementations look like this:
public class PrintedBookDAOImpl implements PrintedBookDAO, GenericDAO<PrintedBook> {
#PersistenceContext(unitName = "pbook-unit", type = PersistenceContextType.EXTENDED)
private EntityManager em;
....
}
I have three modules library-lib(daos) library-service(services) library-web(spring mvc).
Library mvc has controller xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="cz.fi.muni.pa165.library.web" />
<context:component-scan base-package="cz.fi.muni.pa165.service" />
<context:component-scan base-package="cz.fi.muni.pa165.dao" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
and web.xml
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring 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>
When i run the web(on tomcat8) it shows me exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: cz.fi.muni.pa165.service.PrintedBookServiceImpl cz.fi.muni.pa165.library.web.PrintedBookController.pbookService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'printedBookServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private cz.fi.muni.pa165.dao.PrintedBookDAO cz.fi.muni.pa165.service.PrintedBookServiceImpl.pbookDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [cz.fi.muni.pa165.dao.PrintedBookDAO] 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)}
and
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'printedBookServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private cz.fi.muni.pa165.dao.PrintedBookDAO cz.fi.muni.pa165.service.PrintedBookServiceImpl.pbookDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [cz.fi.muni.pa165.dao.PrintedBookDAO] 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)}
also getting this:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pbookDao': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'pbook-unit' is defined
The project is on github https://github.com/Cospel/ProjLibrary
Any ideas how to solve this?
Try adding #Component annotation on PrintedBookDAOImpl, Spring can't find any bean of type PrintedBookDAO in the context.
See this part of the trace :
No qualifying bean of type [cz.fi.muni.pa165.dao.PrintedBookDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
As Jean says, you need to add #Component to any class you wish to autowire. For services, Spring provides some optimizations by using the #Service tag rather than the #Component tag. Similarly, for the DAO layer, Spring provides an optimized #Repository annotation. Use these annotations to enable these classes for component scanning. Then, you shouldn't even need the
setPrintedBookDAO()
method at all, as Spring will take care of the autowiring for you.

Intilaizing a bean with constructor args - WebApplicationContext vs ClassPathApplicationContext

A bean defiend on the applicationContext.xml is getting instantiated using both ClassPathXmlApllicationContext and WebApplicationContext. While using the former the bean is returned as expected but while using the latter, WebApplicationContext, I'm getting a null value.
FYI: Not using the Spring to its full extent. Just used to define a bean and to intialize it. Its a web service application based on jboss.
I defined the WebApplicationContext in my web.xml as below
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<display-name>Service</display-name>
<servlet-name>MService</servlet-name>
<servlet-class>
com.xyz.atop.ws.memb.MServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MService</servlet-name>
<url-pattern>/Service</url-pattern>
</servlet-mapping>
</web-app>
The entry from the applicationContext.xml
<beans ...>
<context:annotation-config />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="helper" name="helper" class="com.xyz.svc.wrapper.Helper">
<constructor-arg type="java.lang.String" value="ABC"/>
</bean>
</beans>
Used the ClassPathApplicationContext (returning a bean instance as expected) in my code as below
private static Helper helper;
public MServiceImpl() {
}
static {
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
helper = (Helper) appContext.getBean("helper");
}
......
......
While using the WebApplicationContext, I tried #Autowired annotation and even tried setter injection. Both the ways I'm getting a null value returned.
The "Helper" class I'm trying to initialize is coming from a jar file which in turn makes calls to a cxf-spring application.
Please look at the above scenario and advise to get rid of the null pointer while using the WebApplicationCOntext.
Ok, spring beans are injected into other spring beans. MService needs to be a bean too. Autowire will then inject the helper into the MService bean. You can't use a static initializer to do this, because that is run at classload time, which is before the application context has loaded. Also, helper shouldn't be static -- that's bad practice -- it makes testing very difficult.
Scenario: Used WebApplicationContext to intialize the beans defined in the applicationCOntext.xml file and received a null while trying to use the instantaited bean object in the code after autowiring.
Issue in this scenario: I'm trying to autowire a spring bean in a class on which Spring has control over.
Solution:
Extending the Servlet class (Class which is not in Spring control) which is the endpoint of my JBOSS WS with Spring's SpringBeanAutowiringSupport class helped me resolve the issue.
Below is the code snippet
public class MServiceImpl extends SpringBeanAutowiringSupport implements MService{
#Autowired
private Helper helper;
public MServiceImpl() {
}
......
......
}
Figured out that using static block to initialize the spring bean is bad approach. Thanks to #Engineer Dollery

spring autowire is not working returning null

i'm learning spring now. here's my sample code. i'm using jersey, spring, hibernate, and mysql for my REST service.
CustomerServiceImpl.java which is REST endpoint (partial code)
package com.samples.service.impl;
#Path("customers")
public class CustomerServiceImpl implements CustomerService {
private static Logger logger = Logger.getLogger(CustomerServiceImpl.class);
#Autowired
CustomerBO customerBO;
here is CustomerBOImpl.java (partial code)
package com.samples.BO.impl;
#Component
public class CustomerBOImpl implements CustomerBO {
#Autowired
CustomerDAO customerDAO;
#Autowired
CustomerAdapter customerAdapter;
CustomerDAOImpl.class
package com.samples.DAO.impl;
#Repository
public class CustomerDAOImpl implements CustomerDAO {
this is applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:property-placeholder location="classpath*:database.properties"/>
<context:component-scan base-package="com.samples"/>
<context:annotation-config />
</beans>
this is first few lines of exception i'm getting.
http-bio-8090-exec-1] [class: CustomerServiceImpl] INFO - list all customers
[http-bio-8090-exec-1] [class: CustomerServiceImpl] INFO - customerBO is null
May 08, 2014 10:55:29 AM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.NullPointerException
at com.samples.service.impl.CustomerServiceImpl.getAllCustomers(CustomerServiceImpl.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvo
this is web.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Employee Service</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:applicationContext.xml
</param-value>
</context-param>
<context-param>
<param-name>initializeContextOnStartup</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.samples.service</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
so if i'm understanding how this works correctly, i'm configuring xml to have my components autoscanned by providing the package under which i want to run autoscan. and for objects that i want to autowire. in CustomerServiceImpl class, i use #autowired for customerBO object which should have been scanned by #Component annotation on CustomerBOImpl.class definition. can you please help why my auto-scan is not picking up autowired customerBO object?
thanks.
I suspect the problem is your CustomerServiceImpl class is being instantiated outside of Spring, either by the servlet container or explicitly in your code. You need to either have Spring instantiate it (by making it a bean, etc) or use <context:spring-configured/>. I'm not sure if the latter will work if the servlet container instantiates the object as it will likely depend on the order in which things occur...
Spring only know to autowire fields that have been marked as beans. From your code CustomerDAO is not a bean. For example to define it as a bean in the xml configuration file you need to add
<bean id="customerDao" class="com.packagesNames.CustomerDaoImpl"/> in the xml file. or to have the class annotated with #Component or to have it defined with #Bean in a #Configuration class.
Jersey 2 and Spring integration is now supported.
Jersey Docs: Chapter 22. Spring DI
Blog: Implementing Jersey 2 Spring Integration
Sample App: Jersey's Hello World Spring WebApp
However, as of this writing, Spring beans can't be injected directly into JAX-RS classes by using Spring XML configuration. Annotations (#Autowired, etc.) must be used.
I had the same problem. My injected bean in the resource class was always coming as NULL.
I spent 2 days trying to figure it out why I can't inject the Spring Bean into the JAX-RS resource class. Then I found the below in the Jersey documentation:
"Limitations:
Spring beans can't be injected directly into JAX-RS classes by using
Spring XML configuration"
Note: I was using Jersey 2 and Spring 3.x in my project.

Can't #Autowire a bean into a controller - NoSuchBeanDefinitionException

I have a spring-mvc web app.
The following code has been simplified and sanitised to protect the guilty. The basic idea is that I have two separate context configuration files: one for MVC, the other for general config stuff.
When Spring goes to wire up the controller, I get:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.ConfigBean com.example.ConfigController.config; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.ConfigBean] 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)}
However, the following code from another servlet works just fine:
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
ConfigBean config = context.getBean(ConfigBean.class);
This suggests to me that the MVC component scanner can't see the config stuff for some reason. I've tried adding
<import resource="config.xml" />
to dispatcher-servlet.xml, but that made no difference. It feels wrong anyway, as I don't want two instances of the config beans. Even manually copying the ConfigBean declaration into dispatcher.xml doesn't fix my problem, which suggests to me I'm doing something really dumb. Any suggestions on what I might be missing?
My detailed configuration is as follows:
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/dispatcher-servlet.xml
/WEB-INF/config.xml
</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
... Some other non-spring stuff ...
</web-app>
dispatcher-servlet.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config />
<context:component-scan base-package="com.example" />
<mvc:annotation-driven />
</beans>
classpath:config.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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean class="com.example.ConfigBean">
<property name="foo" value="bar" />
</bean>
</beans>
ConfigController.java
package com.example;
import com.example.ConfigBean
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping("/config")
public class ConfigController {
#Autowired
private ConfigBean config;
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody ConfigBean getConfig() {
return config;
}
}
It might be because you have added /WEB-INF/dispatcher-servlet.xml to contextConfigLocation in context-param.
It is not required as the web-application context will ready the file based on the displater servlet name
From Spring Doc
Upon initialization of a DispatcherServlet, Spring MVC looks for a
file named [servlet-name]-servlet.xml in the WEB-INF directory of your
web application and creates the beans defined there, overriding the
definitions of any beans defined with the same name in the global
scope.
I think the autowiring is failing due to multiple instance of ConfigBean bean being present. The error message is slightly confusing. You get the same error if the bean is missing or if there are more than one instance.
The problem is with the component scan in the dispatcher-servlet.xml. Assuming that the ConfigBean class is also annotated with #Component or one of it's subtypes two instances will get created. Once for the bean definition in config.xml and once by component scanning.
To fix this you need to change the component-scan to ignore non-controller classes.
<context:component-scan user-default-filters='false'>
<context:include-filter annotation="org.springframework.stereotype.Controller"/>
</context:component-scan>
The lookup in the other servlet class is working because you are accessing the root application context directly.
This did turn out to be pretty dumb. The <context:annotation-config /> directive should have been in config.xml, not dispatcher-servlet.xml.
As I understand it, the annotation stuff is in the parent context, so that's where the directive belongs.

Why Beans on spring-servlet.xml can't access beans in my applicationContext.xml

I have a question here, how beans defined in "applicationContext.xml" could be available to controllers defined in let's say "spring-servlet.xml", so i can skip this kind of errors i have.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/home' defined in ServletContext resource [/WEB-INF/mmapp-servlet.xml]: Cannot resolve reference to bean 'equipementService' while setting bean property 'equipementService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'equipementService' is defined
applicationContext.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="equipementService"
class="mmapp.service.SimpleEquipementService" />
<bean name="equipement1"
class="mmapp.domain.Equipement" />
</beans>
mmapp-servlet.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/home" class="mmapp.web.HelloController">
<property name="equipementService" ref="equipementService" />
</bean>
</beans>
A Spring based web-application normally has multiple runtime Spring application contexts -
A root application context(which is loaded up during the start-up of the servlet container), here is where you normally put your beans for your services - the root application context is loaded up by using a ContextLoaderListener, typically using these entries in your web.xml file:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
One or more web application contexts, which is considered a child of the root application context, holding the beans related to the UI - controllers etc. This is configured by using a Dispatcher Servlet, a special servlet provided by Spring that knows to delegate the calls appropriately to the Spring Container. The beans in the root application context are visible to the beans defined here, BUT not the other way around - this way providing a level of separation between the UI layer and the services layer . This is a typical configuration entry in web.xml file:
<servlet>
<servlet-name>lovemytasks</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mmapp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you have defined the beans this way, the equipementService should be visible to your controller.
I'm not an expert and I'm not sure if this might be a problem, but I have a suggestion.
Could you post your web application descriptor (web.xml)? Does it contain the context-param?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>

Categories