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)文章
Java后臺返回和處理JSon數(shù)據(jù)的方法步驟
這篇文章主要介紹了Java后臺返回和處理JSon數(shù)據(jù)的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09SpringBoot異常處理器的使用與添加員工功能實現(xiàn)流程介紹
設(shè)計完了登錄與退出功能還只完成了冰山一角,經(jīng)過測試發(fā)現(xiàn),我們以url的方式來訪問網(wǎng)站時可以直接跳過登陸頁面進入后臺頁面,這樣顯然是不合理的,下面我們通過異常攔截器+boot來做到訪問限制,以及實現(xiàn)新增員工功能,制作全局異常處理器2022-10-10