1、让我们看看这熟悉的报错
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: In this case,
use RequestContextListener or RequestContextFilter to expose the current request.
2、我的使用场景
在@Async
注解的方法里进行Feign
调用,为什么会出现这个问题尼?是因为我@configurtion
里加了这行代码,因为有业务需求我要从request
里取到header
里的参数
HttpServletRequest request = ((ServletRequestAttributes)
(RequestContextHolder.currentRequestAttributes())).getRequest();
3、那这个报错信息从何而来?
点进RequestContextHolder
这个类,查看源码可知,RequestAttributes - 请求属性
线程拿不到了,所以为null
,然后就throw new IllegalStateException
,以下为源码:
/**
* 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: " +
"In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
}
}
return attributes;
}
4、解决方法
只需要在调用异步方法的外面将RequestAttributes对象设置为子线程共享即可。当然,我们要知道异步线程执行时,ThreadLocal - 线程上下文信息不会自动带过去。当然还有InheritableThreadLocal可以支持将线程上下文传入子线程。
4.2、核心代码
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
RequestContextHolder.setRequestAttributes(sra, true);
4.3、举个栗子
public void childThreadSharing(ScreeningDTO dto) {
// 设置子线程共享
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
RequestContextHolder.setRequestAttributes(sra, true);
// 开始执行异步方法
this.somethingService.executeAsync();
}