Spring MVC execution process and source code analysis

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:

https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/overview.html#overview-modules

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&lt;&gt;();
			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) &amp;&amp; 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 &lt; 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 -&gt; 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

![2021022601-20-01-View-uml(hierarchic group layout)](https://gitee.com/chuchq/blogs-gallery/raw/master/images%20/%202021/2021022601-20-01-View-uml(hierarchic group layout).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

2. References

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>

Tags: Java JavaEE Framework gitee

Posted by hacko on Sun, 10 Apr 2022 23:17:55 +0300