Old-fashioned way :) - used by me till some beautiful Thursday morning ...
public class BeanTest extends HttpServlet {
private EmployerManager employerManager;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Do something amazing with the Spring Bean ...
}
@Override
public void init(ServletConfig config) throws ServletException {
WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
employerManager = applicationContext.getBean("business-logic.EmployerManager", EmployerManager.class);
super.init(config);
}
}
As you see, you can access Spring WebApplicationContext and then the desired bean by its identifier. Main disadvantage of this method is the bean identifier hardcoded into Servlet code. Especially if you are performing automatic component scan in Spring (ex. <context:component-scan base-package="[...].logic.impl" />). In this case you have two choices:- Define the identifier of the bean using annotations:
@Service("business-logic.EmployerManager") public class DefaultEmployerManager implements EmployerManager { ... }
- Use default bean identifier created by Spring in your Servlet - see: Naming autodetected components
Thankfully there are many young people, with open mind, who don't use the old-fashioned ways of doing things, and invent their own, as did my colleague - Bartek. Below you may find method doing the same as the above one, but based on @Autowired annotation usage.
public class BeanTest extends HttpServlet {
@Autowired
private EmployerManager employerManager;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Do something amazing with the Spring Bean ...
}
@Override
public void init(ServletConfig config) throws ServletException {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
super.init(config);
}
}
SpringBeanAutowiringSupport will inject the appropriate Spring Beans into all your Servlet's properties marked with @Autowired annotation. That's all :) No hardcoding of bean names, no worries about future refactorings. Now relax, close your eyes, ...
Hi,
ReplyDeleteI tried your '@Autowired'-approach but it didn't work. Could it be that this only works when using Spring itself, and not SpringMVC.
I have a webapplication that is built on SpringMVC and if I do the following:
@Autowired
private IConfigurationService config;
it remains null although it is declared in the application-context.xml.
Greetings,
Bart
Let me summarize it :) - We've found the reason of Bart's problems together :) - hope that's will be useful for him and maybe for few more people out there :)
ReplyDeleteIn Spring 2.5.6 you can achieve the same "autowiring" effect with the following call:
ReplyDeleteSpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this);
@Guy - it should work in similar way in Spring 3.0 - and just for the reference ;) - method suggested by you uses class loader keyed map: ContextLoader#currentContextPerThread, which is initialized by ContextLoaderListener - so with appropriate setup, using ContextLoaderListener, it should basically do the same :)
ReplyDeleteThanks!
ReplyDeleteExcellent Information!
Solved my issue using JSF 2 with Spring 3 and Servlet.
Thanks so much...
wow!! Thank you!!!!
ReplyDeleteSomehow the beans are not getting injected. I have defined the context loader listener in the web.xml.
ReplyDeletethat works very well. but i'm interested in, why afterPropertiesSet() (implements InitializingBean) is not working.
ReplyDeleteI had that error:
15:21:40,015 ERROR [org.springframework.web.servlet.DispatcherServlet] (http-localhost-127.0.0.1-8080-6) Context initialization failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'selectAttribute' defined in "/D:/java/jbosses/Jboss For OpenID/Jboss711/jboss-as-7.1.1.Final/standalone/deployments/eid-openid-idp-1.0-SNAPSHOT.ear/eid-openid-idp-web-1.0-SNAPSHOT.war/WEB-INF/classes/ge/id/idp/openid/server/controller/SelectAttribute.class": Invocation of init method failed; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) [spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) [spring-beans-3.0.5.RELEASE.jar:3.0.5.RELEASE]
Whoooo HOoooo.... You are amazing! Thanks for sharing!
ReplyDeleteDid you read the Javadoc you link to? For SpringBeanAutoWiringSupport it says in bold
ReplyDelete"If there is an explicit way to access the ServletContext, prefer such a way over using this class. The WebApplicationContextUtils class..."
An implementation respecting this:
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
}