问题
I'm migrating my application from using the web.xml to configure the servlet to use a class implementing WebApplicationInitializer to configure my web application. After migrating everything to that class implementing WebApplicationInitializer I cannot start my application, it complains because it cannot inject a bean that has been declared with a request scope. I added in the servlet context the RequestContextListener but it still failing to inject the bean.
This is the stack trace the server is returning after trying to deploy:
SEVERE: Servlet /TopUp-Services threw load() exception
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.web.context.request.RequestCon textHolder.currentRequestAttributes(RequestContext Holder.java:131)
at org.springframework.web.context.request.AbstractRe questAttributesScope.get(AbstractRequestAttributes Scope.java:41)
at org.springframework.beans.factory.support.Abstract BeanFactory.doGetBean(AbstractBeanFactory.java:330 )
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.findAutowireCandidates(DefaultL istableBeanFactory.java:912)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.doResolveDependency(DefaultList ableBeanFactory.java:855)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.resolveDependency(DefaultListab leBeanFactory.java:770)
at org.springframework.beans.factory.support.Construc torResolver.resolveAutowiredArgument(ConstructorRe solver.java:811)
at org.springframework.beans.factory.support.Construc torResolver.createArgumentArray(ConstructorResolve r.java:739)
at org.springframework.beans.factory.support.Construc torResolver.autowireConstructor(ConstructorResolve r.java:193)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.autowireConstructor(Abs tractAutowireCapableBeanFactory.java:1075)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBeanInstance(Abst ractAutowireCapableBeanFactory.java:979)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.doCreateBean(AbstractAu towireCapableBeanFactory.java:487)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.Abstract BeanFactory$1.getObject(AbstractBeanFactory.java:2 96)
at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistry.getSingleton(DefaultSingleton BeanRegistry.java:223)
at org.springframework.beans.factory.support.Abstract BeanFactory.doGetBean(AbstractBeanFactory.java:293 )
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.preInstantiateSingletons(Defaul tListableBeanFactory.java:628)
at org.springframework.context.support.AbstractApplic ationContext.finishBeanFactoryInitialization(Abstr actApplicationContext.java:932)
at org.springframework.context.support.AbstractApplic ationContext.refresh(AbstractApplicationContext.ja va:479)
at org.springframework.web.servlet.FrameworkServlet.c onfigureAndRefreshWebApplicationContext(FrameworkS ervlet.java:658)
at org.springframework.web.servlet.FrameworkServlet.i nitWebApplicationContext(FrameworkServlet.java:530 )
at org.springframework.web.servlet.FrameworkServlet.i nitServletBean(FrameworkServlet.java:484)
at org.springframework.web.servlet.HttpServletBean.in it(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.j ava:158)
at org.apache.catalina.core.StandardWrapper.initServl et(StandardWrapper.java:1284)
at org.apache.catalina.core.StandardWrapper.load(Stan dardWrapper.java:1090)
at org.apache.catalina.core.StandardContext.loadOnSta rtup(StandardContext.java:5210)
at org.apache.catalina.core.StandardContext.startInte rnal(StandardContext.java:5493)
at org.apache.catalina.util.LifecycleBase.start(Lifec ycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild. call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild. call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.jav a:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker( ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
This is my WebApplicationInitializer implementation class:
package com.topup.services.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.apache.catalina.filters.CorsFilter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.request.RequestCon textListener;
import org.springframework.web.context.support.Annotation ConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterPro xy;
import org.springframework.web.servlet.DispatcherServlet;
public class WebApp implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext)
throws ServletException {
setWebApplicationContext(servletContext);
setFilters(servletContext);
setListeners(servletContext);
}
/**
* Return the WebApplicationContext
*
* @param servletContext
* An instance of {@link javax.servlet.ServletContext}
*/
private void setWebApplicationContext(ServletContext servletContext) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.topup.services");
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"dispatcher", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/TopUp-Services");
}
/**
* Set ServletContext Filters
*
* @param servletContext
* An instance of {@link javax.servlet.ServletContext}
*/
private void setFilters(ServletContext servletContext) {
servletContext.addFilter("corsFilter", new CorsFilter())
.getUrlPatternMappings().add("/TopUp-Services");
servletContext
.addFilter("springSecurityFilterChain",
new DelegatingFilterProxy("springSecurityFilterChain") )
.getUrlPatternMappings().add("/TopUp-Services");
}
/**
* Set ServletContext listeners
*
* @param servletContext
* An instance of {@link javax.servlet.ServletContext}
*/
private void setListeners(ServletContext servletContext) {
servletContext.addListener(new RequestContextListener());
}
}
This is my Configuration class:
package com.topup.services.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configurati on;
import org.springframework.context.annotation.Scope;
import org.springframework.web.context.WebApplicationCont ext;
import com.topup.services.user.service.UserProfileService ;
import com.topup.services.user.service.UserProfileService Impl;
/**
*
* Application configuration class
*
*/
@Configuration
public class AppConfig {
/**
* Returns instance of UserProfileService for the request
*
* @return A request instance of
* {@link com.topup.services.user.service.UserProfileService }
*/
@Bean
@Scope(WebApplicationContext.SCOPE_REQUEST)
public UserProfileService getUserProfileService() {
return new UserProfileServiceImpl();
}
}
Please I'll really appreciate the help trying to figure out how to fix that problem, also if somebody wants to watch the full source code, the project is in this git hub repository.
https://github.com/alexzm1/TopUp-Services/tree/migrate-java8-servlet3-spring4
Hope that you spring gurus can help me with this, Thanks :)
回答1:
Of course Spring can not instantiate and inject your bean during the web application initialization (there is no active request at that time). You need to allow Spring to create so called scoped proxy for that - i.e. instead of your bean a special proxy will be created and used as the injected dependency (the actual target bean will be instantiated in a lazy fashion):
@Bean
@Scope(value=WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.INTERFACES)
public UserProfileService getUserProfileService() {
return new UserProfileServiceImpl();
}
This is similar to <aop:scoped-proxy />
XML configuration
来源:https://stackoverflow.com/questions/23724716/problems-with-bean-declared-as-scope-request-in-servlet-3-0-configuration