SpringMVC process and source code analysis

preface

After learning SpringMVC once, I want to make a summary and review. When REVIEWING and writing the above summary, I found that I did not learn thoroughly, firmly and completely. Videos and books should be combined together, and each teacher’s videos may mention different things, which leads to not being very comprehensive. Notes in books are systematic and comprehensive. At the same time, I myself is a beginner, the following summary may not be perfect, correct, hope to see the god to point out to me, here very grateful.


[TOC]

Spring core module

1. Core modules

Spring Web MVC (hereinafter referred to as SpringMVC) is the framework design of Spring to provide Web applications, which belongs to the framework of the presentation layer. SpringMVC is part of the Spring framework. The Spring framework consists of six modules: Core Container, AOP and device support, data access and integration, Web, message sending, and Test

Picture is from Spring official website 5.0.0.m5:

Docs. Spring. IO/spring – fram…

There are two questions about the Spring5 module diagram: 1. I am not sure why the module map was not found in the Release (stable) version after the 5.0 version on the Spring official website, but it was found in the M (Milestone) version. If anyone found it in the Release (stable) version after the 5.0 version, please leave me a message, thanks. 2. In other posts, see the structure diagram of the Spring5 module like this:

It’s kind of weird where did this graph come from? (Passing god please advise)

For question 2, I found the following information in spring5.2.13.release GA:

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, In the project’s Github Wiki, many visitors are registered in the exhibition.

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.

Web Servlets and Web Reactive are already in different modules based on the above information.

  • Web Servlets: Spring MVC, WebSocket, SockJS, STOMP Messaging.
  • Web Reactive: Spring WebFlux, WebClient, and WebSocket.

IO /projects/sp…

2. Spring Version Naming Rules (Supplement)

There are different versions of Spring mentioned above, so here’s what they mean.

Describe the way instructions meaning
Snapshot The snapshot version An unstable version that is still under development
Release Stable version The function is relatively stable and can be issued externally, but there is a time limit
GA The final version Stands for General Availability
M Milestone version (M stands for Milestone) has some new features or significant releases
RC The final test version Release Candidate, soon to be released as a final Release

SpringMVC process and principle

1. Execution process

SpringMVC execution flowchartSource of pictures: iii. Reference Materials

1.1. Execution process

  • 01. The user sends the request to the DispatcherServlet of the front-end controller (CPU) for processing.

  • 02. After receiving the request, the front-end controller DispatcherServlet invokes the HandlerMapping.

  • HandlerMapping uses the URL of the request to find the Handler that can handle the request. It also provides the interceptor, and constructs the HandlerExecutionChain. The constructed HandlerExecutionChain execution chain object is then returned to the front-end controller DispatcherServlet.

  • 04, front-end controller DispatcherServlet according to the processor mapper HandlerMapping

  • The HandlerAdapter is adapted to call a specific processor (Handler/Controller), that is, a Controller written by the business itself.

  • 06. Controller returns ModelAndView (wrapper object of springmvc, encapsulating model and view together) to HandlerAdapter HandlerAdapter;

  • The HandlerAdapter returns the Controller execution result ModelAndView to the front-end Controller DispatcherServlet.

  • 08. The front-end controller DispatcherServlet calls the view parser ViewReslover to process the ModelAndView.

  • 09, View resolver ViewReslover parses according to the logical View name into the physical View name, namely the specific page address, generates and returns the specific object View (SpringMVC encapsulates the object, is an interface).

  • 10. The front-end controller DispatcherServlet renders the View according to the object View and fills the Model.

  • 11. Front-end controller DispatcherServlet returns a response to the user

1.2 Execution process Description:

1.2.1, Notes 02, 03

(1) Processor mapper: an object in the SpringMVC framework. Classes that implement HandlerMapping interface are called mapper (multiple);

MyController Controller = ctx.getBean(“some”)

(3) The framework stores the found processor objects in a class called HandlerExecutionChain

(4) HandlerExecutionchain: class holds a: handler object (MyController); B: List of all interceptors in the project

(5) Method call :HandlerExecutionChain mappedHandler-gethandler (processedRequest);

1.2.2. Note 04

(1) HandlerExecutionChain finds the corresponding handler mapper HandlerAdapter. (2) Processor adapter: springMVC framework object, need to implement HandlerAdapter interface, (3) processor adapter functions: Execute handler method (call myController.dosome () to get the return value ModelAndView) (4) Call adapter in front controller :HandlerAdapter ha =getHandlerAdapter (mappedHandler.getHandler()); Mv = ha.handle (processedRequest, response, mappedHandler.gethandler ());

Note: (1) View resolver: springMVC object, need to implement the ViewResoler interface (can have more than one) (2) View resolver function: compose view complete path, use prefix, suffix. And create the View object. (3) View is an interface, representing the view, JSP in the framework, HTM1 is not a string representation, but the use of view and his implementation class to represent the view.

InternalResourceview: View class that represents a JSP file. The view parser creates an InternalResourceview class object. Inside this object, there is a property url-/ web-INF /view/show.jsp

1.2.2 SpringMVC Component Description

  • (1). Front-end controller (DispatcherServlet) : receives requests and responds to results, which is equivalent to the CPU of the computer.
  • (2). HandlerMapping: search the processor according to the URL.
  • (3). Handler :(requires programmers to write code to handle logic).
  • (4). HandlerAdapter: The processor will be packaged as an adapter, so that it can support a variety of types of processors, similar to the notebook adapter (adapter mode application).
  • (5). View parser (ViewResovler) : view parsing, multiple returned strings, processing, can be resolved into the corresponding page.

1.2.3 Detailed flow chart of SpringMVC

To sum up, summarize the detailed flow chart of SpringMVC:

Source of pictures: iii. Reference Materials

Second, source code analysis

The following source jar package is spring-webMVC-5.25.release.jar

1. Initialization

1.1, ApplicationContext

ApplicationContext initializes the entry class: The setApplicationContext method of ApplicationObjectSupport, the core of setApplicationContext method is to initialize the container initApplicationContext(context), Subclasses AbstractDetectingUrlHandlerMapping implements the method. Class diagram:UML diagrams:RequestMappingHandlerMapping for annotations @ Controller, @ RequestMapping to define the Controller. During initialization, the three classes are divided roughly as follows:

  • AbstractHandlerMethodMapping define the algorithm processes;
  • RequestMappingInfoHandlerMapping provide matching conditions RequestMappingInfo analytical processing;
  • RequestMappingHandlerMapping RequestMappingInfo was generated according to @ RequestMapping annotations, and at the same time provide isHandler implementation

2. Front-end controller (CENTRAL processing unit) DistepcherServlet

As can be seen from the above flow chart, the front-end controller (CPU) DistepcherServlet is the core of SpringMVC. Check the inheritance of the DistepcherServlet class. UML diagrams:! [in the 2021022601-08 – DispatcherServlet UML diagram] (gitee.com/chuchq/blog… As can be seen from the inheritance relationship: DistepcherServlet –> FrameworkServlet –> HttpServletBean– > HttpServlet The final core method is the Service () method, the core method of servlets. DistepcherServlet does not have a servic() method. On the parent class FrameworkServlet there is a service() method.

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); }}Copy the code

You can see: Frameworkservlet. service(HttpServletRequest Request, HttpServletResponse Response) receives the request and determines whether the request is PATCH. Call the doPost() or doGet() methods of the parent class, depending on the request mode. Use doGet() as an example. DoGet () for 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);
	}
Copy the code

DoGet () also calls processRequest(Request, Response) in the FrameworkServlet class;

/**
	 * Process this request, publishing an event regardless of the outcome.
	 * <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); }}Copy the code

The most critical part of the processRequest(request, response) method calls doService(Request, response); If you look at doService(Request, Response) in the FrameworkServlet class or debug trace, 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>The contract is essentially the same as that for the commonly overridden
	 * {@code doGet} or {@code doPost} methods of HttpServlet.
	 * <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;
Copy the code

Look at the doService(HttpServletRequest Request, HttpServletResponse Response) method in the DispatcherServlet

/**
	 * 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 = newHashMap<>(); 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); }}}}Copy the code

DoDispatch (Request, response) is called from doService(). org.springframework.web.servlet.DispatcherServlet.doDispatch()

/** * Process the actual dispatching to the handler. * <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>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 {
				// File upload related, check whether binary requestprocessedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest ! = request);// Get the controller that handles the current request, also known as the Hanlder handler. This is where the first step is significant. Instead of returning the Controller directly, we return the HandlerExecutionChain request handler chain object, which encapsulates the handler and 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 HandlerAdapter 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; }}// Check the interceptor method before the processor adapter executes
				if(! mappedHandler.applyPreHandle(processedRequest, response)) {return;
				}
				// The processor adapter executes the handler based on what it found and returns the ModelAndView
				// 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); }}}}Copy the code

DoDispatch () is the core code for SpringMVC.

2.1. Find HandlerMapping

First take a look at the HandlerMapping class diagram:

DoDispatch () key code:

HandlerExecutionChain mappedHandler = null;

mappedHandler = getHandler(processedRequest);
Copy the code

MappedHandler is an execution chain HandlerExecutionChain object that encapsulates both the handler and interceptors. The getHandler(processedRequest) method finds the mapping between URL and controller from the processor mapper HandlerMapping and returns it to the front-end controller DispatchServlet. Check the getHandler (processedRequest); Source:

/**
	 * Return the HandlerExecutionChain for this request.
	 * <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) {
					returnhandler; }}}return null;
	}
Copy the code

The debugging code is as follows:From code debugging you can see that there are three objects in handlerMapping:

this.handlerMappings = {ArrayList@4662}  size = 3
 0 = {BeanNameUrlHandlerMapping@4791} 
 1 = {RequestMappingHandlerMapping@4792} 
 2 = {RouterFunctionMapping@4793} 
Copy the code
  • BeanNameUrlHandlerMapping: initialize when urlpath do map storage (XML);
  • RequestMappingHandlerMapping: initialization will be configured in the Controller @ RequestMapping annotation method for mapping storage (annotations);
  • RouterFunctionMapping:

That’s why you need to go to HandlerMapping to find a Handler, because there are different implementations of HandlerMapping:

  • 1. XML
  • 2. Annotation method

Then look at the getHandler(HttpServletRequest Request) method, which iterates through HandlerMappers looking for the controller and returns the Handler of type HandlerExecutionChain.

You can see that in the Handler returned, we get our own code for the Controller class and the interceptor (not written in the demo project, So debugging summary the returned Handler finally is 0 interceptors HandlerExecutionChain with [com. Bjpowernode. Controller. MyController# doSome ()] and 0 interceptorsOpen the idea being debugged in the Controller written by myself for comparison, and find the same:

2.2. Call the HandlerAdapter according to the result returned by the HandlerMapping

Key code in doDispatch() :

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
Copy the code

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)) {
					returnadapter; }}}throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}
Copy the code

Why get a HandlerAdapter: Like getting a HandlerMapping, Spring provides a non-functioning processor adapter. Debugging is as follows:

Check whether the getHandlerAdapter () method in DEBUG mode is: Handler, Adapter, this.handlerAdapters

The following is the copy result: 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.contex t.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcess or,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListe nerFactory,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()"
Copy the code

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.contex t.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcess or,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListe nerFactory,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} 
Copy the code

this.handlerAdapters

this.handlerAdapters = {ArrayList@4658}  size = 4
 0 = {HttpRequestHandlerAdapter@4810} 
 1 = {SimpleControllerHandlerAdapter@4820} / / XML
 2 = {RequestMappingHandlerAdapter@4827} // Annotation mode
 3 = {HandlerFunctionAdapter@4832} 
Copy the code

You can see that four processor adapters were found. Through the DEBUG mode as you can see, the processor adapter HandlerAdapter is to: RequestMappingHandlerAdapter

ha = {RequestMappingHandlerAdapter@4827} 
Copy the code

Check the Interceptor

Key code in doDispatch() :

if(! mappedHandler.applyPreHandle(processedRequest, response)) {return;
				}
org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
Copy the code

ApplyPreHandle (processedRequest, Response)

/**
	 * 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;
	}
Copy the code

The HandlerAdapter executes the Handler (Controller) to return the ModelAndView

Key code in doDispatch() :

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
Copy the code

DEBUG the DEBUG mode, is jumped: org. Springframework. Web. Servlet. MVC) method. The AbstractHandlerMethodAdapter# handle the 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);
	}
Copy the code

If YOU look at the handleInternal(Request, Response, (HandlerMethod) 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 necessarymav = 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;
	}
Copy the code

Notice that the handleInternal(Request, Response, (HandlerMethod) handler) method returns ModelAndView, This completes the processor adapter. The HandlerAdapter executes the Handler (Controller) and returns the result ModelAndView to the front-end Controller DistepchServlet

2.4. ViewResolver

Connect to 2.3: After the front-end controller DistepchServlet receives the ModelAndView returned by the processor adapter HandlerAdapter, there are two cases:

  • (1) If ModelAndView is a logical view

The front end controller DistepchServlet calls the View resolver to find the real View object View through the logical View and return it to the front end controller DistepchServlet.

  • (2) If there is no logical view in ModelAndView:

Example: MappingJackson2JsonView (converts the current data to JSON data without converting the view’s logical name)

To summarize: The ViewResolver interface is mainly used to parse the logical View name passed by the DispatcherServlet of the front-end controller, and return the real View object of the parsing result to the front-end controller DispatcherServlet

ViewResolverd implementation class:

ViewResolver的UML:

View

2.5.1 Functions of view objects

  • (1), the data returned by the controller will be 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 View model and implementation technology of decoupling (refers to the Spring in the org. Springframework. Web. Packages servlet defined in the abstract View interface), as shown in the 2.5.2 View interface diagram.
  • (3) View object View is instantiated by the View parser. Since views are stateless (a new View object is created with each request), there are no thread-safety issues.

2.5.2 View Interface diagram

2.5.3 Implementation class diagram of View

2.5.4 UML diagram of View

2.5.5 Commonly used View classes

The view type Introduction to the
URL view resource diagram InternalResourceView Encapsulate a JSP or other resource into a view. Be view parser InternalResourceViewResolver used by default.
JstlView A subclass of InternalResourceView. This view class is needed if JSTL’s internationalization tags are used in a JSP.
Document view AbstractExcelView Abstract class for Excel document view.
AbstractPdfView Abstract class for PDF document view
The report view ConfigurableJasperReportsView Commonly used JasperReports report view
JasperReportsHtmlView
JasperReportsPdfView
JasperReportsXlsView
JSON view MappingJackson2JsonView Output the data as JSON through the ObjectMapper object of the Jackson framework

2.6. Other important points

2.6.1, DispatcherServlet. Properties

DispatcherServlet. The properties file is in the package for SpringMVC frame:DispatcherServlet. The content of the properties:

# 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
Copy the code

Why can load for SpringMVC different processors mapper HandlerMapping and handlerAdapter processor adapter, it is the framework configuration the DispatcherServlet. The properties files.

Cite reference materials

1. Reference materials

  • SpringMVC flowchart reference address: www.iqiyi.com/w_19s2gmyaz…

  • Flow chart for SpringMVC 2:blog.csdn.net/win7system/ reference address…

  • View View function Address: blog.csdn.net/qq_43193797…

  • IO /projects/sp…

    When writing this article, there may be a small part of reference 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 will add the source of the quotation in the article, thank you!

2. Reference materials

  • W3cschool-spring MVC 4.2.4.RELEASE

    www.w3cschool.cn/spring_mvc_…

  • Reference: www.cnblogs.com/leftthen/ca…


Disclaimer:

Some of the pictures used in this article come from the Internet (see address: iii, Reference resources). If there is any infringement, please contact the blogger to delete them.Copy the code

Reprint statement:

Blogging is not easy, please respect the original author!! Welcome to read, reprint, if it is ** whole article reprint ** please note the original address, author ** at the beginning or end of the article, if it is ** large section of reference ** please note reference link **.Copy the code