Ali p9 teaches you how Spring MVC handles a request process

Spring MVC is the most frequently used part of the Spring series of frameworks. Whether it is Spring Boot or a traditional Spring project, as long as it is a Web project, the Spring MVC part will be used. Therefore, programmers must be proficient in the MVC part. This blog briefly analyzes the process of Spring MVC processing a request

The whole process of a request sent from the client to the server and then processed is actually very complicated. This blog mainly introduces the finishing process (not including the processing process of Filter) when the request reaches the server and is processed by the core component DispatcherServlet.

1. Processing flow analysis
Servlet will call the service() method when processing a request, so the way DispatcherServlet processes the request is also from the service() method (for debugging, it is recommended to start debugging from the service method of DispatcherServlet). FrameworkServlet rewrites the service method of HttpServlet. This service method then calls the processRequest() method of FrameworkServlet, processRequest() calls the doService() method of DispatcherServlet, and finally calls the doDispatcher() method of DispatcherServlet. The method invocation process of the integrated processing request is as above, let's look at the code below:

protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    
    
 
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
    
    
        processRequest(request, response);
    }
    else {
    
    
 //这边调用了HttpServlet的service()方法,但由于FrameWorkServle重写了doGet、doPost等方法,所以最终还是会调用到processRequest方法
        super.service(request, response);
    }
}

Look at the processRequest() method of FrameworkServlet.

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);
 
   try {
    
    
 //这边调用DispatcherServlet的doService()方法
       doService(request, response);
   }
   catch (ServletException ex) {
    
    
       failureCause = ex;
       throw ex;
   }
   catch (IOException ex) {
    
    
       failureCause = ex;
       throw ex;
   }
   catch (Throwable ex) {
    
    
       failureCause = ex;
       throw new NestedServletException("Request processing failed", ex);
   }
 
   finally {
    
    
       resetContextHolders(request, previousLocaleContext, previousAttributes);
       if (requestAttributes != null) {
    
    
           requestAttributes.requestCompleted();
       }
 
       if (logger.isDebugEnabled()) {
    
    
           if (failureCause != null) {
    
    
               this.logger.debug("Could not complete request", failureCause);
           }
           else {
    
    
               if (asyncManager.isConcurrentHandlingStarted()) {
    
    
                   logger.debug("Leaving response open for concurrent processing");
               }
               else {
    
    
                   this.logger.debug("Successfully completed request");
               }
           }
       }
 
       publishRequestHandledEvent(request, response, startTime, failureCause);
   }
}

The specific content of the doService() method will be mentioned later, here is the content of doDispatcher(),

First find the HandlerMethod (with the Method reflection attribute, which corresponds to the method in the Controller) according to the requested path, then match the interceptor corresponding to the path, and construct a HandlerExecutionChain object with the HandlerMethod and the interceptor. The HandlerExecutionChain object is obtained through the methods provided by the HandlerMapping interface. After having HandlerExecutionChain, through the HandlerAdapter object to process the ModelAndView object, when the HandlerMethod internal handle, use various HandlerMethodArgumentResolver implementation classes to process the HandlerMethod parameters, and use various HandlerMethodReturnValueHandler implementation classes to process the return value. The final return value is processed into a ModelAndView object, and the exceptions that occur during this period will be processed by the HandlerExceptionResolver interface implementation class.

Summarize the process of Spring MVC processing a request:

  • First, search for the application context object WebApplicationContext and bind it as an attribute to the request so that the controller and other components can use it.
  • Bind the locale resolver to the request so that other components can obtain information about the region when processing the request (rendering the view, preparing data, etc.). If your application does not need to resolve area-related information;
  • ** Bind the theme parser to the request so that other components (such as views, etc.) can know which theme file to render. Similarly, if you don't need to use theme-related features, just ignore it. If you configure a multipart file processor, the framework will find out whether the file is multipart (divided into multiple parts and uploaded continuously). If so, wrap the request into a MultipartHttpServletRequest object, so that other components in the processing chain can further process it. Regarding Spring's support for multipart file transfer processing;
  • Find a suitable handler for the request. If the corresponding processor can be found, the entire execution chain (pre-processor, post-processor, controller, etc.) associated with the processor will be executed to complete the preparation of the corresponding model or rendering of the view. If the processor returns If it is a model, then the framework will render the corresponding view. If no model is returned (maybe because the front and back processors intercepted the request for some reason, such as security issues), the framework will not render any views. At this time, it is considered that the processing of the request may have been completed by the processing chain (This process is what doService() and doDispatcher() do)
    1. First, the user sends a request——>DispatcherServlet. After receiving the request, the front controller does not process it by itself, but delegates to other resolvers for processing. As a unified access point, perform global process control;

2. DispatcherServlet——>HandlerMapping, HandlerMapping will map the request to a HandlerExecutionChain object (including a Handler processor (page controller) object, multiple HandlerInterceptor interceptors) object, through this strategy mode, it is easy to add new mapping Strategy

3. DispatcherServlet——>HandlerAdapter, HandlerAdapter will package the processor as an adapter, so as to support multiple types of processors, that is, the application of the adapter design pattern, so it is easy to support many types of processors;

4. HandlerAdapter——>Call the processor function processing method, HandlerAdapter will call the real processor function processing method according to the adaptation result to complete the function processing; and return a ModelAndView object (including model data, logical view name) ;

5. The logical view name of ModelAndView -> ViewResolver, ViewResolver will resolve the logical view name into a specific View. Through this strategy mode, it is easy to change other view technologies;

6. View——>Rendering, View will render according to the incoming Model model data. The Model here is actually a Map data structure, so it is easy to support other view technologies;

7. The control right is returned to DispatcherServlet, and DispatcherServlet returns a response to the user, and this process ends.

2. Request flow chart

Still this picture is clearer. It is found that this process cannot be explained clearly based on the code. And the whole process is very long and there is a lot of code, so I won’t post the code. Here is a summary of the functions of the components in the entire process based on this figure:

  • DispatcherServlet: The core controller, all requests will first enter the DispatcherServlet for unified distribution, does it feel a bit like an appearance model?

  • HandlerMapping: The role of this component is to map the URL requested by the user into a HandlerExecutionChain. This HandlerExecutionChain is a combination of HandlerMethod and HandlerInterceptor. Spring will inject many HandlerMapping components by default when it starts, and the most commonly used component is RequestMappingHandlerMapping.
    The above HandlerMethod and HandlerInterceptor components correspond to the methods and interceptors in our Controller, respectively. The interceptor will be executed before the HandlerMethod method is executed

**HandlerAdapter component, the main function of this component is to convert the parameters in HandlerMethod, execute the method, and convert the return value, etc. There are many details involved, including HandlerMethodArgumentResolver, ** HandlerMethodReturnValueHandler, RequestResponseBodyMethodProcessor, and HttpMessageConvert and other components .

  • When the HandlerAdapter component is executed, you will get a ModleAndView component, which represents the view model.

After getting ModleAndView, the postHandle method of the interceptor will be executed.
If any exception occurs during the above execution, it will be handled by the HandlerExceptionResolver.

Finally, the model parser will parse the ModleAndView found above, get a View and return it to the client. The afterCompletion method of the interceptor is also executed before returning to the client.

The above is the detailed content of Spring MVC processing a request. For more information about Spring MVC processing request, please follow the editor or add wx1411943564 remarks (csdn) for more information!

Guess you like

Origin blog.csdn.net/dcj19980805/article/details/115301218