序
本文主要研究下spring mvc的No thread-bound request found异常
分析
该错误信息在RequestContextHolder这个类中,详细如下:
spring-web-4.3.7.RELEASE-sources.jar!/org/springframework/web/context/request/RequestContextHolder.java
public abstract class RequestContextHolder {
private static final boolean jsfPresent =
ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<RequestAttributes>("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal<RequestAttributes>("Request context");
/**
* Return the RequestAttributes currently bound to the thread.
* <p>Exposes the previously bound RequestAttributes instance, if any.
* Falls back to the current JSF FacesContext, if any.
* @return the RequestAttributes currently bound to the thread
* @throws IllegalStateException if no RequestAttributes object
* is bound to the current thread
* @see #setRequestAttributes
* @see ServletRequestAttributes
* @see FacesRequestAttributes
* @see javax.faces.context.FacesContext#getCurrentInstance()
*/
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
RequestAttributes attributes = getRequestAttributes();
if (attributes == null) {
if (jsfPresent) {
attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();
}
if (attributes == null) {
throw new 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.");
}
}
return attributes;
}
/**
* Return the RequestAttributes currently bound to the thread.
* @return the RequestAttributes currently bound to the thread,
* or {@code null} if none bound
*/
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
attributes = inheritableRequestAttributesHolder.get();
}
return attributes;
}
//...
}
解决
在非web下访问了RequestContextHolder.currentRequestAttributes()导致,因此在service层方法里头调用该方法要慎重,为了避免出错,可以再封装一下
public RequestAttributes getRequestAttributesSafely(){
RequestAttributes requestAttributes = null;
try{
requestAttributes = RequestContextHolder.currentRequestAttributes();
}catch (IllegalStateException e){
requestAttributes = new NonWebRequestAttributes();
}
return requestAttributes;
}
NonWebRequestAttributes实现RequestAttributes接口,重写的方法都为空即可
小结
对于在service层使用RequestContextHolder的方法要小心,除了controller层外,调度任务等也可能调用service层的方法。