一、概述
RequestContextHolder是Spring框架中作為HTTP請求上下文綁定的持有者,可以方便地隨時獲取當前請求的HttpServletRequest、HttpServletResponse等信息,這對於Web開發來說是不可或缺的。
在Web應用程序中,一個請求可能會經過多個線程,每個線程都會處理請求的某一個環節。RequestContextHolder可以確保在整個請求處理過程中,我們都能夠訪問到該請求的相關信息。
二、RequestContextHolder分類
Spring框架提供了兩種不同類型的RequestContextHolder:
1、RequestContextHolder使用ThreadLocal保存請求信息
public class RequestContextHolder { private static final ThreadLocal requestAttributesHolder = new NamedThreadLocal("Request attributes"); public static void resetRequestAttributes() { requestAttributesHolder.remove(); } public static void setRequestAttributes(RequestAttributes attributes) { Assert.notNull(attributes, "Only non-null request attributes are permitted"); requestAttributesHolder.set(attributes); } public static RequestAttributes getRequestAttributes() { RequestAttributes attributes = requestAttributesHolder.get(); if (attributes == null) { attributes = new NativeWebRequestAttributes(new MockHttpServletRequest()); requestAttributesHolder.set(attributes); } return attributes; } public static void setRequestAttributes(ServletRequest request, ServletResponse response) { setRequestAttributes(new ServletWebRequest(request, response)); } public static void setRequestAttributes(ServletRequestAttributes attributes) { Assert.notNull(attributes, "ServletRequestAttributes must not be null"); requestAttributesHolder.set(attributes); } public static ServletRequestAttributes getRequestAttributes() { RequestAttributes attributes = getRequestAttributes(); Assert.state(attributes instanceof ServletRequestAttributes, "Request attribute does not support request access"); return (ServletRequestAttributes) attributes; } }
上述代碼中,使用ThreadLocal保存請求的信息,如從HttpServletRequest中獲取的請求信息,這樣可以保證每個線程都能夠訪問到已綁定請求的信息,線程之間不會相互影響。
2、RequestContextHolder使用InheritableThreadLocal保存請求信息
public class RequestContextHolder { private static final InheritableThreadLocal requestAttributesHolder = new NamedInheritableThreadLocal("Request attributes"); public static void resetRequestAttributes() { requestAttributesHolder.remove(); } public static void setRequestAttributes(RequestAttributes attributes) { Assert.notNull(attributes, "Only non-null request attributes are permitted"); requestAttributesHolder.set(attributes); } public static RequestAttributes getRequestAttributes() { RequestAttributes attributes = requestAttributesHolder.get(); if (attributes == null) { attributes = new NativeWebRequestAttributes(new MockHttpServletRequest()); requestAttributesHolder.set(attributes); } return attributes; } public static void setRequestAttributes(ServletRequest request, ServletResponse response) { setRequestAttributes(new ServletWebRequest(request, response)); } public static void setRequestAttributes(ServletRequestAttributes attributes) { Assert.notNull(attributes, "ServletRequestAttributes must not be null"); requestAttributesHolder.set(attributes); } public static ServletRequestAttributes getRequestAttributes() { RequestAttributes attributes = getRequestAttributes(); Assert.state(attributes instanceof ServletRequestAttributes, "Request attribute does not support request access"); return (ServletRequestAttributes) attributes; } }
與第一種方式不同的是,該代碼中使用InheritableThreadLocal保存請求的信息,InheritableThreadLocal是ThreadLocal類的子類,它所保存的值可以被子線程繼承,在子線程中可以訪問到保存的信息,由於InheritableThreadLocal是可繼承的,所以是跨線程的,內存消耗很大,開發時需慎重考慮。
三、RequestContextHolder的用法
1、獲取當前請求的HttpServletRequest
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
2、獲取當前請求的HttpServletResponse
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
3、獲取當前請求的RequestAttributes
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
4、通過RequestContextHolder為當前請求創建的子線程傳遞請求上下文
在多個線程的情況下,如果想把同一個請求傳遞給同一個線程來進行處理,可以先在原請求線程中獲取當前請求上下文,並傳遞到另外一個線程中,代碼示例如下:
原請求線程中:
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
新線程中:
RequestContextHolder.setRequestAttributes(attributes);
5、在Controller層使用RequestContextHolder的示例:
@RestController @RequestMapping("/test") public class TestController { @GetMapping("/getRequest") public String getRequest(HttpServletRequest request) { HttpSession session = request.getSession(); request.setAttribute("name", "test"); return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getAttribute("name").toString(); } }
四、小結
RequestContextHolder是Spring框架中作為HTTP請求上下文綁定的持有者,可以方便地隨時獲取當前請求的HttpServletRequest、HttpServletResponse等信息,能夠確保在整個請求處理過程中,我們都能夠訪問到該請求的相關信息,對Web開發來說非常重要。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/311291.html