一、概述
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-tw/n/311291.html
微信掃一掃
支付寶掃一掃