Spring 單例 httprequest 線程安全

 

@Autowired HttpServletRequest之因此線程安全是由於, httpsevletRequest 儲存在 RequestContextHolder中。 html

  • 每次http請求的doXXX 都會被FrameworkServlet攔截,經過 RequestContextHolder.setxxxxx  寫入TheadLocal。
  • Autowired 獲取request的時候,經過RequestContextHolder.getxxx 從ThreadLocal中獲取。

 

爲何Autowired HttpServletRequest是線程安全的,獲取的方式

 1. 啓動斷點調試,查看request的來源是  WebApplicationContextUtils.RequestObjectFactory.java

 

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中的當前線程的HttpServletRequestmvc

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攔截。ide

 

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

}

 

 

 

參考  this

http://www.javashuo.com/article/p-oamhcvfc-hg.htmlspa

相關文章
相關標籤/搜索