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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM