Spring-MVC- core call process, MySQL million words essence summary

Posted by serg91 on Sun, 02 Jan 2022 23:19:24 +0100

	long startTime = System.currentTimeMillis();
	Throwable failureCause = null;
	
	doService(request, response);

}

> get into`doService`method
> 
> Class: org.springframework.web.servlet.`DispatcherServlet`
```java
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(request);
		try {
			// Call core process
			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);
				}
			}
		}
}

Request call core entry

The request finally enters the doDispatch method

Category: org springframework. web. servlet. DispatcherServlet

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		// Asynchronous management
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

			try {
				// File upload parsing. If the request type is multipart, it will pass
				// MultipartResolver for file upload and parsing
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
				// Matching an appropriate handler for the current request is an important method
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 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;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 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) {
				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 {
				// If it is a multipart request, empty the uploaded multipart resources
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

:: warning knowledge points
In summary, the main functions of getHandler method are as follows:

  • First, get the requested URL from the current Request
  • Then, get the HandlerMethod object from the mapping relationship
  • Next, the HandlerMethod object is encapsulated into the HandlerExecutionChain
  • Finally, during the creation of the HandlerExecutionChain, all interceptors in the whole container (interceptors implementing the HandlerInterceptor interface) will be obtained to match the URL of the current request. If the matching is successful, the interceptors will be placed in the array of HandlerExecutionChain.
    :::

Enter getHandler method

Category: org springframework. web. servlet. DispatcherServlet

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// handlerMappering instance container is not empty
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				// Get the wrapper class of HandlerMethod and filter chain
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

Enter getHandler method

Category: org springframework. web. servlet. handler. AbstractHandlerMapping

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// Get the corresponding HandlerMethod object according to the requested URL
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
		// Get the wrapper class of HandlerMethod and filter chain
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

		if (logger.isTraceEnabled()) {
			logger.trace("Mapped to " + handler);
		}
		else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
			logger.debug("Mapped to " + executionChain.getHandler());
		}
		// Whether it is a cross domain request is to check whether there is the Origin attribute in the request header
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}

		return executionChain;
	}

Enter the getHandlerInternal method

Category: org springframework. web. servlet. handler. AbstractHandlerMethodMapping

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		// Get the URL from the request object, / common/query2
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		this.mappingRegistry.acquireReadLock();
		try {
			// Find the corresponding HandlerMethod object from the mapping relationship according to the URL
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			// Execute beanfactory GetBean to get the Controller instance
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

:: warning knowledge points
The reason why the lookupHandlerMethod method method can get the HandlerMethod object from the mapping relationship is that the AbstractHandlerMethodMapping class implements the InitializingBean interface and establishes the mapping relationship in the afterpropertieset method.
:::

Enter the lookupHandlerMethod method

Category: org springframework. web. servlet. handler. AbstractHandlerMethodMapping

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
			// Whether the matching process conforms to the attribute value in RequestMappingInfo
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		if (!matches.isEmpty()) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				if (logger.isTraceEnabled()) {
					logger.trace(matches.size() + " matching mappings: " + matches);
				}
				if (CorsUtils.isPreFlightRequest(request)) {
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				Match secondBestMatch = matches.get(1);
				// If two RequestMappinginfo are the same, an error is reported
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					String uri = request.getRequestURI();
					throw new IllegalStateException(
							"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
				}
			}
			request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
			handleMatch(bestMatch.mapping, lookupPath, request);
			return bestMatch.handlerMethod;
		}
		else {
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

:: warning knowledge points
The addMatchingMappings method is mainly a matching process to match whether the attribute values in the @ RequestMapping annotation are met

 /*
  * consumes: Specify the submitted content type to process the request,
  * 	For example, application/json, text/html;
  * produces: Specifies the content type to be returned. It is returned only if the (Accept) type in the request header contains the specified type;
  * params:  Specifies that the request must contain some parameter values of yes before the method can handle it.
  * headers:  The specified request must contain some specified header values in order for the method to process the request.
  * */
@RequestMapping(value = "/getUser",
    method = RequestMethod.GET,
    params = "username=jack",
    consumes = "application/json",
    produces = "application/json",
    headers = "Referer=http://www.xx.com/")

:::

Return to getHandler and enter the getHandlerExecutionChain method

Category: org springframework. web. servlet. handler. AbstractHandlerMapping

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		// If not, create a HandlerExecutionChain
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
		// Get current request address: / user/xxx
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		// Add interceptors in HandlerExecutionChain
		// Traverse all interceptors of the spring MVC container
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			// Judge the interceptor type. If it is MappedInterceptor type
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				// Then match the path before adding it to the execution chain
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				// Otherwise, it is added directly to the execution chain
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

:: warning knowledge points
The HandlerInterceptor interceptor in getHandlerExecutionChain is in Spring MVC, and the interceptor in Spring AOP is MethodInterceptor.
:::

After getting the handler corresponding to the current request,

Return to the main process and enter the getHandlerAdapter method

Category: org springframework. web. servlet. DispatcherServlet

/**
 * TODO : Find the appropriate HandlerAdapter object according to the handlerMethod object. The policy pattern is used here
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					// Returns an instance of the HandlerAdapter handler that can be supported
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

:: warning knowledge points

What is a HandlerAdapter
HandlerAdapter is an interface that acts as a bridge between itself and handler objects, resulting in loosely coupled design. HandlerAdapter mainly deals with method parameters, related annotations, data binding, message conversion, return value, calling view parser, etc.

  • RequestMappingHandlerMapping finds the appropriate handler method for the current request.
  • The RequestMappingHandlerAdapter executes this handler method and provides it with the parameters required for the reflection call.

HandlerAdapter UML diagram

Four implementation classes of HandlerAdapter:

  1. SimpleServletHandlerAdapter: adapts the Handler that implements the Servlet interface and calls its service method by default
  1. SimpleControllerHandlerAdapter: adapts to the Handler that implements the Controller interface and calls its handleRequest method by default
  2. HttpRequestHandlerAdapter: adapts to the Handler that implements the HttpRequestHandler interface and calls its handleRequest method by default
  3. RequestMappingHandlerAdapter: it adapts to the method annotated by @ RequestMapping. Generally, it parses one parameter by one and activates it through reflection

HandlerAdapter summary
Handler adapter is a very good embodiment of the extension mechanism in Spring MVC. Through the design mode of HandlerAdapter, DispatcherServlet can support handlers of any format (here, it can support without changing DispatcherServlet). Second, HandlerAdapter implements different implementation classes (policy modes) based on different handlers, The last and most important thing is the analysis of parameters and return values.

:::

:: why does danger use HandlerAdapter adapter mode?
Firstly, there are many definitions of controller. One is annotated with @ controller, and a servlet can be written as a controller. Therefore, the adapter is used for adaptation. Different subclasses implement the HandlerAdapter interface and define their own business logic. Each subclass is adapted to a certain type of controller. With HandlerAdapter, you only need to call the handle method implemented by yourself, The inconsistent details are shielded. For the user, the corresponding processing method can be found directly without any relation to the implementation method. Otherwise, it can only be processed through if and else in the dispatcher servlet.
:::

Prefilter

Return to the main process, enter the applyPreHandle method and the prefilter

Category: org springframework. web. servlet. DispatcherServlet

/**
 * TODO :  Call all the HandlerInterceptor interceptors and call their preHandler methods
 */
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Get all interceptors
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				// Call the interceptor's preHandle method separately
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				// If it fails, record the position of the last interceptor and release it in reverse order
				this.interceptorIndex = i;
			}
		}
		return true;
	}

Return to the main process, enter the handle method and call the specific Controller method

Finally, it will enter the handle method of AbstractHandlerMethodAdapter,

	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return handleInternal(request, response, (HandlerMethod) handler);
	}

Enter the handleInternal method,

Category: org springframework. web. servlet. mvc. method. annotation. RequestMappingHandlerAdapter

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
				// Execute HandlerMethod and return ModelAndView
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			// Execute HandlerMethod and return ModelAndView
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}

Enter the invokeHandlerMethod method,

Category: org springframework. web. servlet. mvc. method. annotation. RequestMappingHandlerAdapter

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			// Get data binding factory @ InitBinder annotation support,
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			// Model factory, which collects @ ModelAttribute annotation methods
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
			//Callable method object
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers != null) {
				//Set parameter parser
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
				// Set return value parser
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			// Set parameter Binding Factory
			invocableMethod.setDataBinderFactory(binderFactory);
			// Set parameter name resolution class
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			// Call the method annotated with @ ModelAttribute. Every request calls a method annotated with @ ModelAttribute
			//The return value of the @ ModelAttribute annotated method is stored in the map of the ModelAndViewContainer object
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);
			// Asynchronous processing
			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				LogFormatUtils.traceDebug(logger, traceOn -> {
					String formatted = LogFormatUtils.formatValue(result, !traceOn);
					return "Resume with async result [" + formatted + "]";
				});
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
			// Controller method call, focus on
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

:: warning knowledge points
The invokeHandlerMethod mainly binds data and parameters, creates a ModelAndViewContainer view container, and initializes it.
:::

Enter the invokeAndHandle method

Category: org springframework. web. servlet. mvc. method. annotation. ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// Specific call logic, focus on
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {


# last

Many people move to the Internet industry every year. To put it bluntly, they are also aiming at high salaries. Whether you are about to enter this industry or want to change careers, learning is essential. As a Java Development and learning have become a part of daily life. If you don't learn, you will be eliminated by this industry, which is also the cruel reality of this industry.

If you're right Java If you are interested and want to change your career, you should take advantage of the opportunity to take action. Maybe this**Limited Edition Java Zero foundation dictionary**Can help you.

Get this**Java Zero foundation dictionary**,**[Just click here to download for free](https://gitee.com/vip204888/java-p7)**

![](https://img-blog.csdnimg.cn/img_convert/8aa110ff656e0797ad67bebdfab38a6a.png)

rRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {


# last

Many people move to the Internet industry every year. To put it bluntly, they are also aiming at high salaries. Whether you are about to enter this industry or want to change careers, learning is essential. As a Java Development and learning have become a part of daily life. If you don't learn, you will be eliminated by this industry, which is also the cruel reality of this industry.

If you're right Java If you are interested and want to change your career, you should take advantage of the opportunity to take action. Maybe this**Limited Edition Java Zero foundation dictionary**Can help you.

Get this**Java Zero foundation dictionary**,**[Just click here to download for free](https://gitee.com/vip204888/java-p7)**

[External chain picture transfer...(img-M0IL4CkX-1628418543876)]

![](https://img-blog.csdnimg.cn/img_convert/6f48e39f279720a93602928e293d9b73.png)

Topics: Java Back-end Interview Programmer