Java子線程調(diào)用RequestContextHolder.getRequestAttributes()方法問題詳解
相信很多開發(fā)過程中都用過RequestContextHolder.getRequestAttributes(),沒錯,我也經(jīng)常用,但今天出現(xiàn)了問題,獲取到的實例是空的
原因是因為我新開了一個子線程,在子線程調(diào)用了RequestContextHolder.getRequestAttributes()。實際獲取到的是空的
然后查看了源碼



ThreadLocal獲取。一個請求到達容器后,Spring會把該請求Request實例通過setRequestAttributes方法 把Request實例放入該請求線程內(nèi)ThreadLocalMap中,然后就可以通過靜態(tài)方法取到。原理就是ThreadLocal,但ThreadLocal不能讓子線程繼承ThreadLocalMap信息,可以使用InherbritableThreadLocal實現(xiàn)子線程信息傳遞。
Spring Boot 默認使用ThreadLocal把Request設(shè)置進請求線程中,這樣如果在請求方法里面另起一個子線程然后再通過getRequestAttributes方法獲取,是獲取不到的
如果想要在子線程獲取,設(shè)置inheritable=true即可,但我一直沒找到在哪里可以設(shè)置,于是自己就寫了個工具類來讓子線程獲取,思路是自定義一個注解,攔截注解,將父線程的ServletRequestAttributes給InheritableThreadLocal,然后在子線程即可獲取
package com.shinedata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestInheritableThread {
}AOP
package com.shinedata.aop;
import com.shinedata.util.context.RequestHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class RequestHolderAspect {
@Before("@annotation(com.shinedata.annotation.RequestInheritableThread)")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes servletRequestAttributes = RequestHolder.getServletRequestAttributes();
RequestHolder.setServletRequestAttributes(servletRequestAttributes);
}
@After("@annotation(com.shinedata.annotation.RequestInheritableThread)")
public void doAfter(JoinPoint joinPoint) {
RequestHolder.removeServletRequestAttributes();
}
}工具類
package com.shinedata.util.context;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
/**
* @ClassName RequestHolder
* @Author yupanpan
*/
public class RequestHolder {
private static final Logger logger = LoggerFactory.getLogger(RequestHolder.class);
public static final String GET = "GET";
public static final String POST = "POST";
public static final String UTF8 = "UTF-8";
public static InheritableThreadLocal<ServletRequestAttributes> servletRequestAttributesInheritableThreadLocal= new InheritableThreadLocal();
public static HttpServletRequest getRequest() {
return getServletRequestAttributes().getRequest();
}
public static HttpServletResponse getResponse() {
return getServletRequestAttributes().getResponse();
}
public static ServletRequestAttributes setServletRequestAttributes(ServletRequestAttributes servletRequestAttributes) {
servletRequestAttributesInheritableThreadLocal.set(servletRequestAttributes);
return servletRequestAttributes;
}
public static void removeServletRequestAttributes() {
servletRequestAttributesInheritableThreadLocal.remove();
}
public static ServletRequestAttributes getServletRequestAttributes() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if(requestAttributes==null){
requestAttributes=servletRequestAttributesInheritableThreadLocal.get();
}
return requestAttributes;
}
}需要在子線程獲取ServletRequestAttributes使用的時候在父方法貼個注解@RequestInheritableThread就行了,父方法里面即使開子線程,子線程里面也能獲取ServletRequestAttributes
補充第二種解決辦法,在開啟新線程之前,將RequestAttributes對象設(shè)置為子線程共享
//開啟新線程之前,添加代碼: ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); RequestContextHolder.setRequestAttributes(sra, true);
到此這篇關(guān)于Java子線程調(diào)用RequestContextHolder.getRequestAttributes()方法問題詳解的文章就介紹到這了,更多相關(guān)Java RequestContextHolder.getRequestAttributes()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Ribbon單獨使用,配置自動重試,實現(xiàn)負載均衡和高可用方式
這篇文章主要介紹了Ribbon單獨使用,配置自動重試,實現(xiàn)負載均衡和高可用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
spring學(xué)習(xí)教程之@ModelAttribute注解運用詳解
這篇文章主要給大家介紹了關(guān)于spring學(xué)習(xí)教程之@ModelAttribute注釋運用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-06-06
Java(springboot) 讀取txt文本內(nèi)容代碼實例
這篇文章主要介紹了Java(springboot) 讀取txt文本內(nèi)容代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02

