This is the 11th day of my participation in the First Challenge 2022

introduce

The DispatcherServlet is a Servlet, called a front-end controller in SpringMVC, that distributes requests based on their path, type, and so on.

Analysis of the

DispatcherServlet class diagram

The red part in the figure above is the Servlet interface, which is implemented and extended in Springmvc. When I first learned javaweb development, I didn’t start by using various MVC frameworks. Instead, I started by writing simple servlets that inherited HttpServlet and overwrote its service methods. Springmvc also inherits the HttpServlet and rewrites its Service method, and configures the servlet to intercept all requests, thus enabling the DispatcherServlet to distribute all requests.

1. Initialization

Because the DispatcherServlet is actually a Servlet, it also follows the life cycle of the Servlet when configured to work. There are three phases in the Servlet lifecycle:

  • init(): Initializes the request
  • service(): Service processing and redirecting after the request is obtained
  • distory(): Destruction after request processing is complete

So when the Tomcat container (servlet container) starts, the initialization method of the servlet is triggered. HttpServletBean implements this method.

@Override
public final void init(a) throws ServletException {

    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if(! pvs.isEmpty()) {try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        }catch (BeansException ex) {
            if (logger.isErrorEnabled()) {
                logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            }
            throwex; }}// The actual processing is here, implemented by the concrete subclass FrameworkServlet
    initServletBean();
}
Copy the code

FrameworkServlet initServletBean method, the real core is initWebApplicationContext ()

protected final void initServletBean(a) throws ServletException {
    long startTime = System.currentTimeMillis();
    try {
        // Initialize the Web container context
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }
    // ...
}
Copy the code

InitWebApplicationContext core processing method

protected WebApplicationContext initWebApplicationContext(a) {
    / /... Omit some code
    // The main logic of this method is to call the onRefresh(ApplicationContext Context) method, which is overridden in the DispatcherServlet class,
    // Complete the initialization of the default implementation class in SpringMVC based on the context obtained above.
    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            // The onRefresh method is overridden in the DispatcherServlet class, so we can see from this that the Spring container is first created and the DispatcherServlet is initialized via onRefresh method after the Spring bean is successfully created.onRefresh(wac); }}// Publish this context to the ServletContext, that is, set the context as an attribute of the ServletContext, with a key value associated with the Servlet class's registered name in web.xml. You can change it
    // publishContext to determine whether to publish to ServletContext. Default is true.
    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}
Copy the code

The onRefresh(WAC) method calls the specific initialization method of the subclass DispatcherServlet.

/** * This implementation calls {@link #initStrategies}.
    */
@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

** Initialize the strategy objects that this servlet uses. * 

May be overridden in subclasses in order to initialize further strategy objects. */

protected void initStrategies(ApplicationContext context) { // Upload the component handler initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); // Processor mapper initHandlerMappings(context); // Processor adapter initHandlerAdapters(context); // Handler exception collator initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); // View handler initViewResolvers(context); initFlashMapManager(context); } Copy the code

2. Distribution logic

  • When a client initiates a request, the request entersDispatcherServletIt does the processingHandlerThe lookup.
  • First according to the request informationHttpServletRequest, traverses all registeredhandlerMappings. The returned structure isHandlerExecutionChainContains a specific processorhandlerAnd the interceptorinterceptorThe structure of the.
  • Access to theHandlerExcecutionChainThen, based on the specific processor, through allhandlerAdapters, return supportedHandlerAdapter.
  • In the access toHandlerAdapterAfter that, perform specifichandlerBefore, the execution is iteratedHandlerExecutionChainPreinterceptor method for interceptors inpreHandle().If an interceptor’s pre-method executes the post-methodfalseIs executed directly from the current nodeafterCompletion()To terminate the request after execution.
  • According to theHandlerAdapterProcessor adapters execute specific processorsHandlerLogic.
  • Specific at execution completionhandlerAfter that, the execution is iteratedHandlerExecutionChainOf the interceptorpostHandleMethods.
  • HandlerIt will return after executionModeAndView.
  • In the normal case of execution, execution is iterated after rendering the template and before the request is returnedHandlerExecutionChainOf the interceptorafterCompletionMethods.

3. Set up the SpringMVC container

According to the class diagram DispatcherServlet is also realized the ApplicationContextAware interface, and xxxAware interface, is a postProcessBeforeInitialization upon initial springbean extension points, Performed by the class ApplicationContextAwareProcessor to specific logic, is simply pass by setApplicationContext ApplicationContext to initializing the bean.

This is how you pass the Spring container (applicationContext) to the DispatcherServlet in SpringBoot. Until to actually perform the DispatcherServlet initialization method when enclosing applicationContext is not empty, so in initWebApplicationContext () method, go first if logic, This is why SpringBoot won’t eventually produce parent-child containers.