Interpretation of spring MVC dispatcher Servlet

Posted by michelledebeer on Sat, 01 Jan 2022 15:49:16 +0100

 

In the whole Spring MVC framework, dispatcher servlet is at the core. It is responsible for coordinating and organizing different components to complete request processing and return response. DispatcherServlet is the unified entry of Spring MVC, and all requests pass through it. Dispatcher servlet is a front-end Controller configured on the web In the XML file, the servlet intercepts matching requests according to specific rules defined by itself and distributes them to the target Controller for processing. When initializing the dispatcher servlet, the framework looks for a servlet named [servlet name] - servlet in the WEB-INF directory of the web application XML file, and define the relevant Beans there, rewriting any Beans defined in the global. Before looking at the dispatcher servlet class, let's take a look at the general flow of request processing:

  1. Tomcat starts, instantiate DispatcherServlet, initializes its init(), and completes it in the initialization process: web. Loading initialization parameters in XML; Establish webapplicationcontext (IOC container of spring MVC); Initialize components;
  2. The client sends a request, and Tomcat receives the request. If it matches the dispatcher servlet on the web According to the mapping path configured in XML, Tomcat forwards the request to dispatcher servlet for processing;
  3. DispatcherServlet takes out all HandlerMapping instances from the container (each instance corresponds to an implementation class of the HandlerMapping interface) and traverses it. Each HandlerMapping will find the Handler (executive program, such as method in Controller) that handles the request through its own implementation class according to the request information, The Handler and a bunch of handlerinterceptors (interceptors) are encapsulated into a HandlerExecutionChain object. Once a HandlerMapping can find the Handler, it will exit the loop;
  4. DispatcherServlet takes out the HandlerAdapter component, finds the HandlerAdapter object that can handle the Handler from all handleradapters according to the found Handler;
  5. Execute the preHandler() of all interceptors in the HandlerExecutionChain, then execute the Handler with the HandlerAdapter, get the ModelAndView after execution, and then call the postHandler() of the interceptor in turn;
  6. Use ViewResolver to parse ModelAndView or Exception (which can be parsed into ModelAndView) into View, then View will call render() and render the page according to the data in ModelAndView;
  7. Finally, call the interceptor's afterCompletion() in turn, and this time the request ends.


 

 

The core of spring MVC is DispatcherServlet, which is essentially an HttpServlet. DispatcherSevlet is responsible for distributing requests. All requests are uniformly distributed through it.

  let's take a general look at the process of spring MVC request processing:

 

 

 


  the user sends a request to the server, and the request will be sent to the dispatcher servlet Parse the request URL to obtain the request resource identifier (URI), then call HandlerMapping to obtain all relevant objects configured by the Handler (including a Handler processor object and multiple HandlerInterceptor interceptor objects) according to the URI, and finally return it in the form of HandlerExecutionChain object.
  DispatcherServlet Select an appropriate HandlerAdapter according to the obtained Handler. Extract the model data in the Request, fill in the Handler input parameter, and start executing the Handler (Controller). In the process of filling in the parameters of the Handler, Spring will help you do some extra work according to your configuration:

  • Httpmessageconverter: converts the request message (such as Json, xml and other data) into an object, and converts the object into the specified response information
  • Data conversion: perform data conversion on the request message. Such as converting String to Integer, Double, etc
  • Data format: format the request message. Such as converting a string into a formatted number or a formatted date
  • Data verification: verify the validity of data (length, format, etc.), and store the verification results in BindingResult or Error

   after the Handler completes execution, it sends a message to the dispatcher servlet Return a ModelAndView object; According to the returned ModelAndView, select a suitable viewresolver to return to the dispatcher servlet; ViewResolver Combine Model and View to render the View, and finally return the rendering results to the client.

 

Several important components of the dispatcher servlet class:

    // File upload component
    /** MultipartResolver used by this servlet */
    private MultipartResolver multipartResolver;

    // Resource location component
    /** LocaleResolver used by this servlet */
    private LocaleResolver localeResolver;

    // Topic resolution component
    /** ThemeResolver used by this servlet */
    private ThemeResolver themeResolver;

    // Processor mapper component collection
    /** List of HandlerMappings used by this servlet */
    private List<HandlerMapping> handlerMappings;

    // Processor adapter component collection
    /** List of HandlerAdapters used by this servlet */
    private List<HandlerAdapter> handlerAdapters;

    // Exception handling parser collection
    /** List of HandlerExceptionResolvers used by this servlet */
    private List<HandlerExceptionResolver> handlerExceptionResolvers;

    // View name parser
    /** RequestToViewNameTranslator used by this servlet */
    private RequestToViewNameTranslator viewNameTranslator;

    // Redirection and FlashMap Storage components
    /** FlashMapManager used by this servlet */
    private FlashMapManager flashMapManager;

    // View resolution component collection
    /** List of ViewResolvers used by this servlet */
    private List<ViewResolver> viewResolvers;

 

Processing logic of doDispatch function

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        // Get the asynchronous request processing manager. When the business logic is complex (or for other reasons) and the request thread needs to be delegated to another thread to avoid blocking, the processor will be used to process the request
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                // Check whether it is a file upload request. If so, it will request Package as one MultipartHttpServletRequest(Inherited from HttpServletRequest)request
                processedRequest = checkMultipart(request);

                //If it is different from the original request, it indicates that it is a file upload request, otherwise it is an ordinary request
                multipartRequestParsed = (processedRequest != request);

                // Obtain the processor request execution chain according to the request, otherwise the request cannot be processed by the application
                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Get processor adapter
                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // If it is GET perhaps HEAD Request, call HandlerAdapter.getLastModified Methods look at the goal Controller Method is not available for the request lastModified Logic, if any, use ServletWebRequest.checkNotModified Logical judgment current lastModfied Value sum http header If it has not expired, set 304 header and return and end the whole request process. Otherwise continue.
                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                // Before processing the request, first call the processor's execution chain front-end method, which mainly calls the interceptor's front-end method
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Use the processor adapter to process the request and return the model view object
                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                // Check whether the asynchronous processing has started. If so, the current thread will no longer continue to process the request and return directly
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                // If the model view object is not null If there is a view, set the name of the view
                applyDefaultViewName(processedRequest, mv);

                // After processing the request, the processor executes the chain post method, which is mainly called the post method of the interceptor.
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }

            // Handle requests and distribute processing results, such as handling exceptions, parsing view content, etc
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            // If the asynchronous request processing manager has started processing the request, it will call the callback function of the processor execution chain, which is mainly called internally AsyncHandlerInterceptor Type of interceptor
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                //Close open resources due to file upload requests
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

 

 

 

 

REF

https://blog.csdn.net/zero__007/article/details/88650174

https://blog.csdn.net/u012777670/article/details/82701132

https://www.jianshu.com/p/9b7883c6a1a0