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.
Four implementation classes of HandlerAdapter:
- SimpleServletHandlerAdapter: adapts the Handler that implements the Servlet interface and calls its service method by default
- SimpleControllerHandlerAdapter: adapts to the Handler that implements the Controller interface and calls its handleRequest method by default
- HttpRequestHandlerAdapter: adapts to the Handler that implements the HttpRequestHandler interface and calls its handleRequest method by default
- 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)