Have you ever use @Autowired HttpServletRequest in Spring? At first glance, It seems quite strange, since we know basically there are 4 kinds of variables in Spring: Singleton, Protototype, Request, Session. I thought it’s a singleton instance, so it must be wrong to use the injection in such way. But, after some googling, It turns out that it’s OK to use in such a  way. But the tutorial or the answers from stackoverflow just says that the @autowired HttpServeltRequest will load the actual current request whenever we actually use the variable. But they apparently do not mention why, so I come with my own exploring of spring source code to find the reason. The version of spring I choose is 4.3.7.RELEASE. The conjunction of the spring-based container with the servlet-context container is ContextLoaderListener . Whenever the web context is bootstrapped, it will initialize the servlet context. We often use ServletContextListenerto register our self-defined business logic for the servlet context. So does the spring application context. Inside the ContextLoaderListener bootstrap and shutdown spring WebApplicationContext. As you can see down below:
  1. initialize the context
/**
 * Initialize the root web application context.
 */
@Override
public void contextInitialized(ServletContextEvent event) {
  initWebApplicationContext(event.getServletContext());
}


/**
 * Close the root web application context.
 */
@Override
public void contextDestroyed(ServletContextEvent event) {
  closeWebApplicationContext(event.getServletContext());
  ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
 
  1. configure the webapplicationcontext
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        // ...
        
        try {
            // Store context in local instance variable, to guarantee that
            // it is available on ServletContext shutdown.
            if (this.context == null) {
                this.context = createWebApplicationContext(servletContext);
            }
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent ->
                        // determine parent for root web application context, if any.
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }  
       }

}


  1. refresh the context
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    // any initialization logic
    customizeContext(sc, wac);
    wac.refresh();
}
  And that’s the whole process of the initialization logic of spring based web application.   So Let’s take a little deeper. What does the  wac.refresh()method do? I find the implementation in  AbstractApplicationContext.java file. Here is the actual logic:
      @Override
public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();

    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);

    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);

    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);

    // Initialize message source for this context.
    initMessageSource();

    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();

    // Initialize other special beans in specific context subclasses.
    onRefresh();

    // Check for listener beans and register them.
    registerListeners();
    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);

    // Last step: publish corresponding event.
    finishRefresh();
  }
}
  Basically, it is about 9 steps that we should do to start up a spring container.   We choose the implementation of the postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)method. The web related context of spring is AbstractRefreshableWebApplicationContext. we find the implementation of  postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory).
@Override
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
  }
  Let’s take a little deeper, go to the registerWebApplicationScopes.
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
    beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
    beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
    beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
    if (sc != null) {
      ServletContextScope appScope = new ServletContextScope(sc);
      beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
      // Register as ServletContext attribute, for ContextCleanupListener to detect it.
      sc.setAttribute(ServletContextScope.class.getName(), appScope);
    }

    beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
    beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
    if (jsfPresent) {
      FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
    }
  }
See, at the bootstrap phase, the spring context will register 4 kinds of different kinds of variables for their own resolve logic. The above code just says that if you want to find a bean of type ServletRequest, just look for the RequestObjectFactory instance. It will handle all the real retrieve. Let’s dig into RequestObjectFactory:  
private static class RequestObjectFactory implements ObjectFactory, 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;
}

From above, we know that every time we want to read the value of ServletRequest bean, the spring container will delegate it to RequestObjectFactory, and delegate to RequestContextHolder. Let’s dig into RequestContextHolder:  
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
    RequestAttributes attributes = getRequestAttributes();
    // ... jsf special feature
    return attributes;
  }

public static RequestAttributes getRequestAttributes() {
    RequestAttributes attributes = requestAttributesHolder.get();
    if (attributes == null) {
      attributes = inheritableRequestAttributesHolder.get();
    }
    return attributes;
  }
private static final ThreadLocal requestAttributesHolder =
      new NamedThreadLocal("Request attributes");
Follow the chain, we know that the currentRequestAttributes() is actually requesting a static ThreadLocal variable. Till now, we know that every time when we try to access the HttpServletRequest variable, we are just requesting a value that’s stored inside of a static ThreadLocal variable.     But, since when do we store our request inside a static ThreadLocal variable?   Let’s follow the chain from setting the requestAttributesHolder:
public static void setRequestAttributes(RequestAttributes attributes) {
    setRequestAttributes(attributes, false);
  }
By use of code assistance, we know that there are FrameworkServlet, RequestContextListener that try to use the above method to set up the ThreadLocal variable besides the testing class.   Let’s see the RequestContextListenerfirst. The RequestContextListenerimplements ServletRequestListener. ServletRequestListener is a servlet standard interface that fulfills the developer’s need to modify the request in and out of a web component. Here we can expose the request to the current thread. As the doc says, the RequestContextListener is maily for the use with third-party servelts, e.g. the JSF FacesServlet. Within Spring’s own web support, DispatcherServelt’s processing is perfercely sufficient.   So, let’s see the FrameworkServlet. FrameworkServlet is the base servlet for Spring’s web framework. It’s just like an ordinary java servlet. So let’s take doGet entrance for example.
@Override
  protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    processRequest(request, response);
  }


protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;

   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   LocaleContext localeContext = buildLocaleContext(request);

   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

   initContextHolders(request, localeContext, requestAttributes);

   
   doService(request, response);
   
}

protected ServletRequestAttributes buildRequestAttributes(
      HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {

   if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
      return new ServletRequestAttributes(request, response);
   }
   else {
      return null;  // preserve the pre-bound RequestAttributes instance
   }
}
  As you can see from processRequest method, every time the raw HttpServletRequest comes, it will first try to retrieve the previous request, if the request is null, create one, then call the initContextHolders method. Let’s dig into initContextHolders method:
private void initContextHolders(
      HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {

    if (localeContext != null) {
      LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
    }
    if (requestAttributes != null) {
      RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
    }
    if (logger.isTraceEnabled()) {
      logger.trace("Bound request context to thread: " + request);
    }
  }
  Finally, we solve the question we mention earlier. we discover that every time when a raw http request comes, the Spring will try to set the current http servlet request into a global static ThreadLocal variable so that later the request can be retrieve back and forth even in mutli-thread evvironment.