日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springframework包下的RequestContextHolder类和ServletRequestAttributes类的源码和使用

發布時間:2024/9/30 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springframework包下的RequestContextHolder类和ServletRequestAttributes类的源码和使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • RequestContextHolder源碼:
  • 項目中使用RequestContextHolder
    • 在項目中獲得完整請求路徑
    • 關于ServletRequestAttributes源碼 :
    • 關于 HttpServletRequest和 HttpServletResponse
    • cookie的寫入和獲得

1.通過RequestContextHolder的靜態方法可以隨時隨地取到當前請求的request對象
該類可以用于獲得客戶端請求的上下文

RequestContextHolder源碼:

Holder class to expose the web request in the form of a thread-bound RequestAttributes object. The request will be inherited by any child threads spawned by the current thread if the inheritable flag is set to true.
Use RequestContextListener or org.springframework.web.filter.RequestContextFilter to expose the current web request. Note that org.springframework.web.servlet.DispatcherServlet already exposes the current request by default.
package org.springframework.web.context.request;
翻譯:
Holder類以線程綁定的RequestAttributes對象的形式公開web請求。如果可繼承標志設置為true,該請求將被當前線程的所有子線程繼承。

使用RequestContextListener或org.springframework.web.filter.RequestContextFilter來暴露當前的web請求。注意,org.springframework.web.servlet.DispatcherServlet已經默認暴露了當前請求。

源碼:

//import javax.faces.context.FacesContext; import org.springframework.core.NamedInheritableThreadLocal; import org.springframework.core.NamedThreadLocal; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils;public abstract class RequestContextHolder {private static final boolean jsfPresent = ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");public RequestContextHolder() {}public static void resetRequestAttributes() {requestAttributesHolder.remove();inheritableRequestAttributesHolder.remove();}public static void setRequestAttributes(@Nullable RequestAttributes attributes) {setRequestAttributes(attributes, false);}public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {if (attributes == null) {resetRequestAttributes();} else if (inheritable) {inheritableRequestAttributesHolder.set(attributes);requestAttributesHolder.remove();} else {requestAttributesHolder.set(attributes);inheritableRequestAttributesHolder.remove();}}@Nullablepublic static RequestAttributes getRequestAttributes() {RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();if (attributes == null) {attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();}return attributes;}public static RequestAttributes currentRequestAttributes() throws IllegalStateException {RequestAttributes attributes = getRequestAttributes();if (attributes == null) {if (jsfPresent) {attributes = RequestContextHolder.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;}private static class FacesRequestAttributesFactory {private FacesRequestAttributesFactory() {}@Nullablepublic static RequestAttributes getFacesRequestAttributes() {FacesContext facesContext = FacesContext.getCurrentInstance();return facesContext != null ? new FacesRequestAttributes(facesContext) : null;}} }

個人理解用ThreadLocal保證了數據間的隔離性

項目中使用RequestContextHolder

用一個servlet工具類:

public class ServletUtils {/*** 定義移動端請求的所有可能類型*/private final static String[] agent = { "Android", "iPhone", "iPod", "iPad", "Windows Phone", "MQQBrowser" };/*** 獲取String參數*/public static String getParameter(String name){return getRequest().getParameter(name);}public static ServletRequestAttributes getRequestAttributes(){RequestAttributes attributes = RequestContextHolder.getRequestAttributes();//這里用RequestContextHolder獲得ServletRequestAttributes return (ServletRequestAttributes) attributes;}/*** 獲取request*/public static HttpServletRequest getRequest(){return getRequestAttributes().getRequest();}/*** 獲取response*/public static HttpServletResponse getResponse(){return getRequestAttributes().getResponse();}/*** 獲取session*/public static HttpSession getSession(){return getRequest().getSession();}/*** 將字符串渲染到客戶端* * @param response 渲染對象* @param string 待渲染的字符串* @return null*/public static String renderString(HttpServletResponse response, String string){try{response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().print(string);}catch (IOException e){e.printStackTrace();}return null;}

通過這個工具類獲得cookies:
Cookie[] cookies = ServletUtils.getRequest().getCookies();

在項目中獲得完整請求路徑

/*** 獲取完整的請求路徑,包括:域名,端口,上下文訪問路徑* * @return 服務地址*/public String getUrl(){HttpServletRequest request = ServletUtils.getRequest();return getDomain(request);}public static String getDomain(HttpServletRequest request){StringBuffer url = request.getRequestURL();String contextPath = request.getServletContext().getContextPath();//getServletContext()方法:獲取這個ServletRequest最后被分派到的servlet上下文。返回:這個ServletRequest最后被分派到的servlet上下文return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();}

關于ServletRequestAttributes源碼 :

/*** Servlet-based implementation of the {@link RequestAttributes} interface.** <p>Accesses objects from servlet request and HTTP session scope,* with no distinction between "session" and "global session".** @author Juergen Hoeller* @since 2.0* @see javax.servlet.ServletRequest#getAttribute* @see javax.servlet.http.HttpSession#getAttribute*/ public class ServletRequestAttributes extends AbstractRequestAttributes {/*** Constant identifying the {@link String} prefixed to the name of a* destruction callback when it is stored in a {@link HttpSession}.*/public static final String DESTRUCTION_CALLBACK_NAME_PREFIX =ServletRequestAttributes.class.getName() + ".DESTRUCTION_CALLBACK.";protected static final Set<Class<?>> immutableValueTypes = new HashSet<>(16);static {immutableValueTypes.addAll(NumberUtils.STANDARD_NUMBER_TYPES);immutableValueTypes.add(Boolean.class);immutableValueTypes.add(Character.class);immutableValueTypes.add(String.class);}private final HttpServletRequest request;@Nullableprivate HttpServletResponse response;@Nullableprivate volatile HttpSession session;private final Map<String, Object> sessionAttributesToUpdate = new ConcurrentHashMap<>(1);/*** Create a new ServletRequestAttributes instance for the given request.* @param request current HTTP request*/public ServletRequestAttributes(HttpServletRequest request) {Assert.notNull(request, "Request must not be null");this.request = request;}/*** Create a new ServletRequestAttributes instance for the given request.* @param request current HTTP request* @param response current HTTP response (for optional exposure)*/public ServletRequestAttributes(HttpServletRequest request, @Nullable HttpServletResponse response) {this(request);this.response = response;}/*** Exposes the native {@link HttpServletRequest} that we're wrapping.*/public final HttpServletRequest getRequest() {return this.request;}/*** Exposes the native {@link HttpServletResponse} that we're wrapping (if any).*/@Nullablepublic final HttpServletResponse getResponse() {return this.response;}/*** Exposes the {@link HttpSession} that we're wrapping.* @param allowCreate whether to allow creation of a new session if none exists yet*/@Nullableprotected final HttpSession getSession(boolean allowCreate) {if (isRequestActive()) {HttpSession session = this.request.getSession(allowCreate);this.session = session;return session;}else {// Access through stored session reference, if any...HttpSession session = this.session;if (session == null) {if (allowCreate) {throw new IllegalStateException("No session found and request already completed - cannot create new session!");}else {session = this.request.getSession(false);this.session = session;}}return session;}}private HttpSession obtainSession() {HttpSession session = getSession(true);Assert.state(session != null, "No HttpSession");return session;}@Overridepublic Object getAttribute(String name, int scope) {if (scope == SCOPE_REQUEST) {if (!isRequestActive()) {throw new IllegalStateException("Cannot ask for request attribute - request is not active anymore!");}return this.request.getAttribute(name);}else {HttpSession session = getSession(false);if (session != null) {try {Object value = session.getAttribute(name);if (value != null) {this.sessionAttributesToUpdate.put(name, value);}return value;}catch (IllegalStateException ex) {// Session invalidated - shouldn't usually happen.}}return null;}}@Overridepublic void setAttribute(String name, Object value, int scope) {if (scope == SCOPE_REQUEST) {if (!isRequestActive()) {throw new IllegalStateException("Cannot set request attribute - request is not active anymore!");}this.request.setAttribute(name, value);}else {HttpSession session = obtainSession();this.sessionAttributesToUpdate.remove(name);session.setAttribute(name, value);}}@Overridepublic void removeAttribute(String name, int scope) {if (scope == SCOPE_REQUEST) {if (isRequestActive()) {removeRequestDestructionCallback(name);this.request.removeAttribute(name);}}else {HttpSession session = getSession(false);if (session != null) {this.sessionAttributesToUpdate.remove(name);try {session.removeAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name);session.removeAttribute(name);}catch (IllegalStateException ex) {// Session invalidated - shouldn't usually happen.}}}}@Overridepublic String[] getAttributeNames(int scope) {if (scope == SCOPE_REQUEST) {if (!isRequestActive()) {throw new IllegalStateException("Cannot ask for request attributes - request is not active anymore!");}return StringUtils.toStringArray(this.request.getAttributeNames());}else {HttpSession session = getSession(false);if (session != null) {try {return StringUtils.toStringArray(session.getAttributeNames());}catch (IllegalStateException ex) {// Session invalidated - shouldn't usually happen.}}return new String[0];}}@Overridepublic void registerDestructionCallback(String name, Runnable callback, int scope) {if (scope == SCOPE_REQUEST) {registerRequestDestructionCallback(name, callback);}else {registerSessionDestructionCallback(name, callback);}}@Overridepublic Object resolveReference(String key) {if (REFERENCE_REQUEST.equals(key)) {return this.request;}else if (REFERENCE_SESSION.equals(key)) {return getSession(true);}else {return null;}}@Overridepublic String getSessionId() {return obtainSession().getId();}@Overridepublic Object getSessionMutex() {return WebUtils.getSessionMutex(obtainSession());}/*** Update all accessed session attributes through {@code session.setAttribute}* calls, explicitly indicating to the container that they might have been modified.*/@Overrideprotected void updateAccessedSessionAttributes() {if (!this.sessionAttributesToUpdate.isEmpty()) {// Update all affected session attributes.HttpSession session = getSession(false);if (session != null) {try {for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {String name = entry.getKey();Object newValue = entry.getValue();Object oldValue = session.getAttribute(name);if (oldValue == newValue && !isImmutableSessionAttribute(name, newValue)) {session.setAttribute(name, newValue);}}}catch (IllegalStateException ex) {// Session invalidated - shouldn't usually happen.}}this.sessionAttributesToUpdate.clear();}}/*** Determine whether the given value is to be considered as an immutable session* attribute, that is, doesn't have to be re-set via {@code session.setAttribute}* since its value cannot meaningfully change internally.* <p>The default implementation returns {@code true} for {@code String},* {@code Character}, {@code Boolean} and standard {@code Number} values.* @param name the name of the attribute* @param value the corresponding value to check* @return {@code true} if the value is to be considered as immutable for the* purposes of session attribute management; {@code false} otherwise* @see #updateAccessedSessionAttributes()*/protected boolean isImmutableSessionAttribute(String name, @Nullable Object value) {return (value == null || immutableValueTypes.contains(value.getClass()));}/*** Register the given callback as to be executed after session termination.* <p>Note: The callback object should be serializable in order to survive* web app restarts.* @param name the name of the attribute to register the callback for* @param callback the callback to be executed for destruction*/protected void registerSessionDestructionCallback(String name, Runnable callback) {HttpSession session = obtainSession();session.setAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name,new DestructionCallbackBindingListener(callback));}@Overridepublic String toString() {return this.request.toString();}}

關于 HttpServletRequest和 HttpServletResponse

關于servlet的介紹:
客戶端的網絡請求首先會被Http服務器接收(也叫Web服務器、web容器,其需要提供web應用運行所需的環境,接收客戶端的Http請求);

Web服務器根據請求的路徑將請求轉交給對應的Servlet容器(也稱Servlet引擎,為Servlet的運行提供環境支持,可以理解為tomcat或其他服務器);

Servlet容器根據對應的虛擬路徑(@WebServlet中配置的)來加載Servlet,如果Serlvet沒有被實例化則創建該Servlet的一個實例(調用init方法);

Servlet容器根據用戶的HTTP請求,創建一個ServletRequest對象(HTTP的請求信息被封裝在其中)和一個可以對HTTP請求進行響應的ServletResponse對象(類似于寄信,并在信中說明回信的地址),然后調用HttpServlet中重寫的service(ServletRequest req, ServletResponse res)方法,并在這個方法中,將ServletRequest、ServletResponse這兩個對象向下轉型,得到我們非常熟悉的HttpServletRequest和HttpServletResponse兩個對象,然后將客戶端的請求轉發到HttpServlet中protected修飾的service(HttpServletRequest req, HttpServletResponse resp)

cookie的寫入和獲得

/*** 獲得指定Cookie的值* * @param request 請求對象* @param response 響應對象* @param name 名字* @param isRemove 是否移除* @return 值*/public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name,boolean isRemove){String value = null;Cookie[] cookies = request.getCookies();if (cookies != null){for (Cookie cookie : cookies){if (cookie.getName().equals(name)){try{value = URLDecoder.decode(cookie.getValue(), "utf-8");}catch (UnsupportedEncodingException e){e.printStackTrace();}if (isRemove){cookie.setMaxAge(0);response.addCookie(cookie);}}}}return value;} /*** 設置 Cookie* * @param name 名稱* @param value 值* @param maxAge 生存時間(單位秒)* @param uri 路徑*/public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge){Cookie cookie = new Cookie(name, null);cookie.setPath(path);cookie.setMaxAge(maxAge);//該方法用于設置cookie的生存時間,try{cookie.setValue(URLEncoder.encode(value, "utf-8"));//URLEncoder.encode()可以對要傳遞的中文進行編碼a ,如果url參數值含有特殊字符時,需要使用 url 編碼。否則可能特殊字符會消失}catch (UnsupportedEncodingException e){e.printStackTrace();}response.addCookie(cookie);}

總結

以上是生活随笔為你收集整理的springframework包下的RequestContextHolder类和ServletRequestAttributes类的源码和使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。