@Autowired HttpServletRequest之因此線程安全是由於, httpsevletRequest 儲存在 RequestContextHolder中。 html
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