zoukankan      html  css  js  c++  java
  • Spring 单例 httprequest 线程安全

    @Autowired HttpServletRequest之所以线程安全是因为, httpsevletRequest 储存在 RequestContextHolder中。 

    • 每次http请求的doXXX 都会被FrameworkServlet拦截,通过 RequestContextHolder.setxxxxx  写入TheadLocal。
    • Autowired 获取request的时候,通过RequestContextHolder.getxxx 从ThreadLocal中获取。

    为什么Autowired HttpServletRequest是线程安全的,获取的方式

     1. 启动断点调试,查看request的来源是  WebApplicationContextUtils.RequestObjectFactory.

    2. 查看源码 WebApplicationContextUtils.RequestObjectFactory, request 来自于 RequestContextHolder.currentRequestAttributes() 方法

    class WebApplicationContextUtils {
        @SuppressWarnings("serial")
        private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
    
            @Override
            public ServletRequest getObject() {
                return currentRequestAttributes().getRequest();
            }
    
            @Override
            public String toString() {
                return "Current HttpServletRequest";
            }
        }

        private static ServletRequestAttributes currentRequestAttributes() {
            RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
            if (!(requestAttr instanceof ServletRequestAttributes)) {
                throw new IllegalStateException("Current request is not a servlet request");
            }
            return (ServletRequestAttributes) requestAttr;
        }
    }

    3. 上述方法的attributes来自于线程安全的ThreadLocal中的当前线程的HttpServletRequest

    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");

        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();
                }
            }
        }

     

    设置的方式

    request是什么时候设置到threadlocal中去的呢? 是在Springmvc的dispatcherServlet的父类FrameworkServlet里操作的.。 doGet 、doPost 、doXXX方法都是委托processRequest方法去做的. 也就是说请求方法会被FrameworkServlet的processRequest拦截。

    class FrameworkServlet {
       protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
              .....
            initContextHolders(request, localeContext, requestAttributes);
       }
    
        private void initContextHolders(HttpServletRequest request,
                @Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
    
            ......
            if (requestAttributes != null) {
                RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
            }
            ....
        }
    
    }

    参考  

    https://www.cnblogs.com/abcwt112/p/7777258.html

  • 相关阅读:
    三元运算
    sys and os
    print.format
    while loop
    线段树模板
    Round #431 (Div.2)
    D. Make a Permutation!
    Round #411 (Div.2)
    Round #432 (Div.2)
    Round #433 (Div.2)
  • 原文地址:https://www.cnblogs.com/webglcn/p/10659821.html
Copyright © 2011-2022 走看看