Spring MVC process and source code analysis
preface
After learning spring MVC once, I want to make a summary and review. When reviewing and writing the following summary, I found that I didn't learn thoroughly, firmly and completely. Videos and books should be combined. What each teacher's videos may mention is inconsistent, which also leads to not very comprehensive. The note taking system that can be said in books is comprehensive. At the same time, I am also a beginner. The following summary may not be perfect and correct. I hope to see the great God point it out to me. Thank you very much.
[TOC]
1, Spring core module
1. Core module
Spring Web MVC (hereinafter referred to as spring MVC) is the framework design of Web applications provided by spring, which belongs to the framework of presentation layer. Spring MVC is part of the spring framework. The spring framework includes roughly six modules: Core Container, AOP and device support, data access and integration, Web, message sending and Test
The picture comes from Spring official website 5.0.0 M5:
There are two questions about the Spring 5 module diagram: 1. I don't know why I can't find the module diagram in the Release version (stable version) after version 5.0 on the Spring official website, but I can find it in the M (milestone version). If someone finds it in the Release version (stable version) after version 5.0, please leave me a message. Thank you. 2. In other blog posts, we can see that the structure diagram of Spring 5 module is as follows:
It's strange. Where did this picture come from? (please point out the great God passing by)
For question 2, I'm in spring 5 2.13. In release GA, the following information is found:
Copy the above information:
Spring Framework Documentation
Version 5.2.13.RELEASE
What's New, Upgrade Notes, Supported Versions, and other topics, independent of release cadence, are maintained externally on the project's Github Wiki.
Overview | history, design philosophy, feedback, getting started. |
---|---|
Core | IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP. |
Testing | Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient. |
Data Access | Transactions, DAO Support, JDBC, O/R Mapping, XML Marshalling. |
Web Servlet | Spring MVC, WebSocket, SockJS, STOMP Messaging. |
Web Reactive | Spring WebFlux, WebClient, WebSocket. |
Integration | Remoting, JMS, JCA, JMX, Email, Tasks, Scheduling, Caching. |
Languages | Kotlin, Groovy, Dynamic Languages. |
According to the above information, Web Servlet and Web Reactive belong to different modules.
- Web Servlet: Spring MVC, WebSocket, SockJS, STOMP Messaging.
- Web Reactive: Spring WebFlux, WebClient, WebSocket.
Official Spring documentation: https://spring.io/projects/spring-framework#learn/
2. Spring version naming rules (supplementary)
The above mentioned different versions of Spring. Here's the meaning of each version.
Description mode | explain | meaning |
---|---|---|
Snapshot | Snapshot version | An unstable version that is still under development |
Release | Stable version | The function is relatively stable and can be released externally, but there is a time limit |
GA | Official edition | Represents the widely available stable version (General Availability) |
M | Milestone release | (M means Milestone) it has some new functions or meaningful versions |
RC | Final version | Release Candidate (final test), which will be released as the official version |
2, Spring MVC process and principle
1. Execution process
Spring MVC execution flow chart
< font size = "4" color = "red" > Image Source: III. reference materials < / font >
1.1 implementation process
-
01. The user sends a request to the dispatcher servlet of the front-end controller (central processing unit) for processing.
-
02, the front controller DispatcherServlet calls the processor mapper HandlerMapping after receiving the request.
-
03. The processor mapper HandlerMapping finds the Handler that can be processed and the relevant interceptor interceptor according to the URL and other information requested by the request, constructs the HandlerExecutionChain execution chain, and then returns the constructed HandlerExecutionChain execution chain object to the front-end controller DispatcherServlet.
-
04. The front-end controller DispatcherServlet is based on the processor mapper HandlerMapping
-
05. The handler adapter of the processor adapter calls the specific processor (Handler/Controller) through adaptation, that is, the Controller written by itself in the business.
-
06. After processing, the Controller returns ModelAndView (the encapsulated object of spring MVC, encapsulating the model and view together) to the processor adapter HandlerAdapter;
-
07. The processor adapter HandlerAdapter returns the Controller execution result ModelAndView to the front-end Controller DispatcherServlet.
-
08. The DispatcherServlet of the front-end controller calls the view parser viewrestover to process ModelAndView.
-
09. After being parsed by the View resolver, the View resolver resolves the logical View name into the physical View name, that is, the specific page address, and generates and returns the specific object View (spring MVC encapsulated object, which is an interface).
-
10. The front-end controller DispatcherServlet renders the View according to the object View and fills the Model.
-
11. The front-end controller DispatcherServlet returns a response to the user
1.2 description of execution process:
1.2.1 description 02 and 03
(1) Processor mapper: an object in the spring MVC framework. The framework calls all classes that implement the HandlerMapping interface mapper (multiple);
(2) Function of processor mapper: obtain the processor object (MyController controller = ctx.getBean("some") from the springmvc container object upon request
(3) The framework saves the found processor objects in a class called handler execution chain
(4) HandlerExecutionchain: class holds a: processor object (MyController); b: all interceptors in the project list < handlerinterceptor >
(5) Method call: HandlerExecutionChain mappedHandler - getHandler (processedRequest);
1.2.2 note 04
(1) The handlerexecutionchain finds the corresponding processor mapper handleradapter. (2) processor adapter: objects in the springmvc framework, need to implement the HandlerAdapter interface, (3) the processor adapter function: execute the processor method (call MyController.doSome() get the return value ModelAndView) (4) call the adapter in the front controller: HandlerAdapter ha =getHandlerAdapter (mappedHandler.getHandler()); (5) Execute processor method: MV = ha handle (processedRequest, response, mappedHandler.getHandler());
Section 08 Description: (1) view parser: objects in spring MVC need to implement viewresolver interface (there can be multiple) (2) function of view parser: form the complete path of the view, and use prefix and suffix. And create a view object. (3) view is an interface that represents the view. In the framework, JSP and htm1 are not represented by string, but by view and its implementation classes.
Internalresourceview: a view class that represents a JSP file. The view parser will create an internalresourceview class object. Inside this object, there is a property URL - / WEB-INF / view / show jsp
1.2.2 spring MVC component description
- (1). Front end controller (dispatcher servlet): receives the request and responds to the result, which is equivalent to the CPU of the computer.
- (2). Handler mapping: find the processor according to the URL
- (3). Processor (Handler): (requires programmers to write code to process logic)
- (4). Handler adapter: the processor will be packaged as an adapter, so that it can support many types of processors, similar to the adapter of notebook (Application of adapter mode)
- (5). View resolver: parses the view, returns multiple strings, processes them, and parses them into corresponding pages
1.2.3 detailed flow chart of spring MVC
To sum up, the detailed flow chart of spring MVC is summarized below:
< font size = "4" color = "red" > Image Source: III. reference materials < / font >
2, Source code analysis
The following source code comes from jar package: spring-webmvc-5.25 RELEASE. jar
1. Initialize
1.1,ApplicationContext
ApplicationContext initialization entry class: the setApplicationContext method of ApplicationObjectSupport. The core part of the setApplicationContext method is to initialize the container initApplicationContext(context). The subclass AbstractDetectingUrlHandlerMapping implements this method. Class diagram: UML diagram:
RequestMappingHandlerMapping for annotation @Controller Requester, @ When initializing the following three classes:
- AbstractHandlerMethodMapping defines the whole algorithm flow;
- RequestMappingInfoHandlerMapping provides parsing and processing of matching condition RequestMappingInfo;
- RequestMappingHandlerMapping generates RequestMappingInfo according to the @ RequestMapping annotation and provides isHandler implementation
2. Front end controller (CPU) DistepcherServlet
From the above flow chart, we can see that the front-end controller (CPU) DistepcherServlet is the core of spring MVC. Check the inheritance of the DistepcherServlet class. UML diagram:! [2021022601-08-dispatcher servlet UML diagram]( https://gitee.com/chuchq/blogs-gallery/raw/master/images%20/%202021/2021022601-08-DispatcherServlet UML diagram png) from the inheritance relationship: DistepcherServlet -- > FrameworkServlet -- > httpservletbean -- > httpservlet. That means that the DistepcherServlet class is also a Servlet class, and the final core method is the service() method, that is, the core method of the Servlet. Find the service() method. There is no servic() method in the DistepcherServlet. There is a service() method in the parent FrameworkServlet. The source code is as follows:
org.springframework.web.servlet.FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)
/** * Override the parent class implementation in order to intercept PATCH requests. */ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } }
You can see: FrameworkServlet Service (HttpServletRequest request, httpservletresponse response) gets the request and determines whether the current request is a PATCH request. If not, call the service () method of the parent class. To use the service method in the parent class is to call the doPost(),doGet() method in the class. According to different request methods, then go to doPost() or doGet(), taking doGet() as an example. The doGet() source code of the FrameworkServlet class:
/** * Delegate GET requests to processRequest/doService. * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead}, * with a {@code NoBodyResponse} that just captures the content length. * @see #doService * @see #doHead */ @Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
doGet() calls processRequest(request, response) in the FrameworkServlet class;
/** * Process this request, publishing an event regardless of the outcome. * </p><p>The actual event handling is performed by the abstract * {@link #doService} template method. */ 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 { doService(request, response); } catch (ServletException | 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(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); } }
In the processRequest(request, response) method, the most critical one calls doService(request, response); Check the doService(request, response) or debugging trace in the FrameworkServlet class. It can be seen that doService(request, response) is implemented by the subclass DispatcherServlet.
Source code:
org.springframework.web.servlet.FrameworkServlet.doService(HttpServletRequest request, HttpServletResponse response)
/** * Subclasses must implement this method to do the work of request handling, * receiving a centralized callback for GET, POST, PUT and DELETE. * </p><p>The contract is essentially the same as that for the commonly overridden * {@code doGet} or {@code doPost} methods of HttpServlet. * </p><p>This class intercepts calls to ensure that exception handling and * event publication takes place. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure * @see javax.servlet.http.HttpServlet#doGet * @see javax.servlet.http.HttpServlet#doPost */ protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
View the doservice (HttpServletRequest request, httpservletresponse) method in the dispatcher servlet
/** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<string, object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration<!--?--> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this.flashMapManager != null) { FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } try { doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }
In the doService() method of dispatcherservlet, doDispatch(request, response) is finally called. Check the source code as follows: org springframework. web. servlet. DispatcherServlet. doDispatch()
/** * Process the actual dispatching to the handler. * </string,></p><p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * </p><p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { // Related to file upload, judge whether it is a binary request processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Get the controller that handles the current request, also known as the handler here. The meaning of the first step is reflected here Instead of directly returning the controller, the returned handler executionchain request processor chain object encapsulates the handler and interceptor interceptors // Determine handler for the current request. mappedHandler = getHandler(processedRequest); // If handler is empty, 404 is returned if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } //3. Get the handler adapter that processes the request // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //The method of checking the interceptor before the processor adapter executes if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //The processor adapter executes the handler and returns ModelAndView according to the found // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); 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); } 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 (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
It can be seen that doDispatch() is the core code of spring MVC. Analyze doDispatch():
2.1. Find processor mapper HandlerMapping
First, take a look at the handler mapping class diagram of the processor mapper:
doDispatch() key code:
HandlerExecutionChain mappedHandler = null; mappedHandler = getHandler(processedRequest);
mappedHandler is an execution chain handler executionchain object, which encapsulates handler and interceptor interceptors. getHandler(processedRequest) method is to find the corresponding relationship between url and controller from handler mapping of processor mapper and return it to DispatchServlet, the front-end controller. View getHandler(processedRequest); Source code:
/** * Return the HandlerExecutionChain for this request. * </p><p>Tries all handler mappings in order. * @param request current HTTP request * @return the HandlerExecutionChain, or {@code null} if no handler could be found */ @Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
The debugging code is as follows: From the code debugging, we can see that there are three objects in handlerMapping:
this.handlerMappings = {ArrayList@4662} size = 3 0 = {BeanNameUrlHandlerMapping@4791} 1 = {RequestMappingHandlerMapping@4792} 2 = {RouterFunctionMapping@4793}
-
BeanNameUrlHandlerMapping: urlpath will be stored as mapping (xml) during initialization;
-
RequestMappingHandlerMapping: during initialization, the method of configuring @ RequestMapping annotation in the Controller will be mapped and stored (annotation);
-
RouterFunctionMapping: (this object is not well understood) that's why we need to find a Handler in HandlerMapping, because the processor mapper HandlerMapping has different implementations:
-
1. xml mode
-
2. Annotation method
Next, look at the getHandler(HttpServletRequest request) method. First traverse the handlermapers, find the controller, and then return the Handler of type HandlerExecutionChain of the execution chain.
You can see that among the returned handlers, we get the controller class encoded by ourselves and the interceptor (not written in the demonstration project, so the last Handler returned by debugging summary is 0 interceptors) HandlerExecutionChain with [com.bjpowernode.controller.MyController#doSome()] and 0 interceptors Open the idea being debugged and compare it with the Controller written by yourself. It is found that it is consistent:
2.2. Call the processor adapter HandlerAdapter according to the result returned by the processor mapper handlerapping
Key codes in doDispatch():
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
The source code is as follows:
/** * Return the HandlerAdapter for this handler object. * @param handler the handler object to find an adapter for * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error. */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
Why get the processor adapter HandlerAdapter: like getting the processor mapper handleradapping, Spring provides a processor adapter that doesn't work. Commissioning is as follows:
Check the of getHandlerAdapter () method in DEBUG mode: handler, adapter, this handlerAdapters
Here is the result of the copy: handler
handler = {HandlerMethod@4792} "com.bjpowernode.controller.MyController#doSome()" logger = {LogAdapter$JavaUtilLog@4858} bean = {MyController@4859} beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy" beanType = {Class@3782} "class com.bjpowernode.controller.MyController" method = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()" bridgedMethod = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()" parameters = {MethodParameter[0]@4861} responseStatus = null responseStatusReason = null resolvedFromHandlerMethod = {HandlerMethod@4863} "com.bjpowernode.controller.MyController#doSome()" interfaceParameterAnnotations = null description = "com.bjpowernode.controller.MyController#doSome()"
adapter
adapter = {RequestMappingHandlerAdapter@4827} customArgumentResolvers = null argumentResolvers = {HandlerMethodArgumentResolverComposite@4833} initBinderArgumentResolvers = {HandlerMethodArgumentResolverComposite@4834} customReturnValueHandlers = null returnValueHandlers = {HandlerMethodReturnValueHandlerComposite@4835} modelAndViewResolvers = null contentNegotiationManager = {ContentNegotiationManager@4836} messageConverters = {ArrayList@4837} size = 4 requestResponseBodyAdvice = {ArrayList@4838} size = 0 webBindingInitializer = null taskExecutor = {SimpleAsyncTaskExecutor@4839} asyncRequestTimeout = null callableInterceptors = {CallableProcessingInterceptor[0]@4840} deferredResultInterceptors = {DeferredResultProcessingInterceptor[0]@4842} reactiveAdapterRegistry = {ReactiveAdapterRegistry@4844} ignoreDefaultModelOnRedirect = false cacheSecondsForSessionAttributeHandlers = 0 synchronizeOnSession = false sessionAttributeStore = {DefaultSessionAttributeStore@4845} parameterNameDiscoverer = {DefaultParameterNameDiscoverer@4846} beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy" sessionAttributesHandlerCache = {ConcurrentHashMap@4848} size = 0 initBinderCache = {ConcurrentHashMap@4849} size = 0 initBinderAdviceCache = {LinkedHashMap@4850} size = 0 modelAttributeCache = {ConcurrentHashMap@4851} size = 0 modelAttributeAdviceCache = {LinkedHashMap@4852} size = 0 order = 2147483647 supportedMethods = null allowHeader = "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS" requireSession = false cacheControl = null cacheSeconds = -1 varyByRequestHeaders = null useExpiresHeader = false useCacheControlHeader = true useCacheControlNoStore = true alwaysMustRevalidate = false servletContext = {ApplicationContextFacade@4754} logger = {LogAdapter$JavaUtilLog@4854} applicationContext = {XmlWebApplicationContext@4665} "WebApplicationContext for namespace 'myweb-servlet', started on Tue Mar 02 23:25:35 CST 2021" messageSourceAccessor = {MessageSourceAccessor@4855}
this.handlerAdapters
this.handlerAdapters = {ArrayList@4658} size = 4 0 = {HttpRequestHandlerAdapter@4810} 1 = {SimpleControllerHandlerAdapter@4820} //XML mode 2 = {RequestMappingHandlerAdapter@4827} //Annotation method 3 = {HandlerFunctionAdapter@4832}
You can see that four processor adapters were found. Through the DEBUG mode, we can see that the handler adapter of the processor adapter obtained this time is: RequestMappingHandlerAdapter
ha = {RequestMappingHandlerAdapter@4827}
2.3. Check Interceptor
Key codes in doDispatch():
if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
applyPreHandle(processedRequest, response) source code:
/** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
2.3. Processor adapter HandlerAdapter executes Handler (Controller) and returns ModelAndView
Key codes in doDispatch():
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
DEBUG mode debugging, is to jump to: org springframework. web. servlet. mvc. method. Abstracthandlermethodadapter #handle source code is as follows:
/** * This implementation expects the handler to be an {@link HandlerMethod}. */ @Override @Nullable public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
Next, look at the handleinternal (request, response, (handler method) handler) method, org springframework. web. servlet. mvc. method. annotation. RequestMappingHandlerAdapter#handleInternal
@Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No HttpSession available -> no mutex necessary mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No synchronization on session demanded at all... mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }
Note that the return value of the handleInternal(request, response, (HandlerMethod) handler) method is ModelAndView. Here, the processor adapter HandlerAdapter executes the Handler (Controller) and returns the result ModelAndView to the front-end Controller DistepchServlet
2.4. View resolver
connect to 2.3: after the front-end controller DistepchServlet receives the ModelAndView returned by the processor adapter HandlerAdapter, there are two situations:
- (1) If there is a logical View in ModelAndView, the front-end controller DistepchServlet calls the View parser ViewResolver to find the real View object View through the logical View and returns it to the front-end controller DistepchServlet.
- (2) If there is a non logical view in ModelAndView: for example: MappingJackson2JsonView (convert the current data into JSON data, and there is no need to convert the logical name of the view)
To sum up: the ViewResolver interface of the View parser is mainly used to parse the logical View name passed by the front-end controller DispatcherServlet, and return the real View object View of the parsing result to the front-end controller DispatcherServlet
Implementation class of viewresolver:
UML of ViewResolver:
2.5 View
2.5.1 function of view object
- (1) The data returned by the controller is processed and rendered, and finally returned to the client for display to the user, mainly to complete the forwarding or redirection operation.
- (2) In order to realize the decoupling between the View model and the specific implementation technology (referring to the abstract View interface defined by Spring in the org.springframework.web.servlet package), see 2.5.2 View interface diagram for details.
- (3) The view object view is instantiated by the view parser. Because the view is stateless (a new view object will be created for each request), there will be no thread safety problem
2.5.2 View interface diagram
2.5.3 implementation class diagram of View
2.5.4 UML diagram of View
.png)
2.5.5 common View classes
< / P > < Table > < tbody > < tr > < TD colSpan = "2" > view type < / td > < td > Introduction < / td > < / TR > < TD rowspan = "2" > URL view resource map < / td > < td > internalresourceview < / td > < td > encapsulates JSP or other resources into a view. It is used by default by the view parser InternalResourceViewResolver</ Td > < / TR > < tr > < td > jstlview < / td > < td > subclass of internalresourceview. If JSTL's internationalization tag is used in JSP, you need to use this view class</ Td > < / TR > < tr > < TD rowspan = "2" > document view < / td > < td > abstractexcelview < / td > < td > abstract class of Excel document view</ Td > < / TR > < tr > < td > abstractpdfview < / td > < td > abstract class of PDF document view < / td > < / TR > < TD rowspan = "4" > report view < / td > < td > configurablejasperreportsview < / td > < TD rowspan = "4" >The commonly used JasperReports report view < / td > < / TR > < tr > < td > jasperreportshtmlview < / td > < / TR > < tr > < td > jasperreportspdfview < / td > < / TR > < tr > < td > jasperreportsxlsview < / td > < / TR > < tr > < TD > JSON view < / td > < td > mappingjackson2jsonview < / td > < td > outputs the data in JSON through the ObjectMapper object of the Jackson frame < / td > < / TR > < / tbody > < / Table >
2.6 other important points
2.6.1,DispatcherServlet.properties
DispatcherServlet. The properties file is in the spring MVC rack package: DispatcherServlet.properties content:
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver= org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver= org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping= org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\ org.springframework.web.servlet.function.support.RouterFunctionMapping org.springframework.web.servlet.HandlerAdapter= org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\ org.springframework.web.servlet.function.support.HandlerFunctionAdapter org.springframework.web.servlet.HandlerExceptionResolver= org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator= org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver= org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager= org.springframework.web.servlet.support.SessionFlashMapManager
Why spring MVC can load different processor mapper HandlerMapping and processor adapter handlerAdapter is because the framework is configured with this dispatcher servlet Properties file.
3, References cited
1. References
-
Spring MVC flowchart reference address: https://www.iqiyi.com/w_19s2gmyazh.html
-
Spring MVC flowchart reference address 2: https://blog.csdn.net/win7system/article/details/90674757
-
View action reference address: https://blog.csdn.net/qq_43193797/article/details/84928603
-
Official Spring documentation: https://spring.io/projects/spring-framework#learn/
When writing this article, there may be a few references to other materials, but I can't find the source of the original text when sorting it out. If the author of the original text sees it, please contact me in time. I add the source in the article. Thank you!
2. References
-
Reference: w3cschool spring MVC 4.2.4 Release Chinese document:
https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/
-
reference resources: https://www.cnblogs.com/leftthen/category/790002.html
Disclaimer:
Some of the pictures used in this article come from the Internet (see address: III. reference materials). If there is infringement,Please contact the blogger to delete.
Reprint statement:
**Blogging is not easy, please respect the original author!!** Welcome to read and reprint. If yes**Reprint the whole article**Please at the beginning or end of the article **Indicate the original address and author**,If it is**Large segment reference**please **Note reference link**.
</handlerinterceptor>