Spring mvc 从一个http请求分析DispatcherServlet的工作过程
发布日期:2021-09-30 11:34:38 浏览次数:10 分类:技术文章

本文共 18580 字,大约阅读时间需要 61 分钟。

开发工具 Intellij IDEA 

目标、调试 请求http://localhost:8080/coffee/helloworld

dispatcher
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
/WEB-INF/dispatcher-servlet.xml
1
dispatcher
/coffee
url-pattern 拦截所有的/coffee开头的请求
@Controller@RequestMapping("coffee")public class HelloControler{	@RequestMapping("helloworld")	public @ResponseBody String helloWorld() {		System.out.println("xxx");		return "hello 222 world";	}}
/** * Delegate GET requests to processRequest/doService. * 

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 */@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}

org.springframework.web.servlet.FrameworkServlet
/**	 * Process this request, publishing an event regardless of the outcome.	 * 

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);//******* doService *********// } catch (ServletException ex) { failureCause = ex; throw ex; } catch (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(); } if (logger.isDebugEnabled()) { if (failureCause != null) { this.logger.debug("Could not complete request", failureCause); } else { if (asyncManager.isConcurrentHandlingStarted()) { logger.debug("Leaving response open for concurrent processing"); } else { this.logger.debug("Successfully completed request"); } } } publishRequestHandledEvent(request, response, startTime, failureCause); } }

接着看一下 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 {		if (logger.isDebugEnabled()) {			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +					" processing " + request.getMethod() + " request for [" + getRequestUri(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
attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap
(); Enumeration
attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) { 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()); 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); } } } }
然后看一下 最关键的方法
/**	 * Process the actual dispatching to the handler.	 * 

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. *

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 { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request);// **********************************根据request查找mappedHandler 也就是一个Controller // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } 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) { // 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); } } } }

 看一下Spring如何匹配url 然后查找对应的Controller 
/**	 * Return the HandlerExecutionChain for this request.	 * 

Tries all handler mappings in order. * @param request current HTTP request * @return the HandlerExecutionChain, or {@code null} if no handler could be found */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }

private List
handlerMappings;
handlerMappings 是包含俩元素
BeanNameUrlHandlerMapping DefaultAnnotationHandlerMapping package org.springframework.web.servlet.handler; /**	 * Look up a handler for the given request, falling back to the default	 * handler if no specific one is found.	 * @param request current HTTP request	 * @return the corresponding handler instance, or the default handler	 * @see #getHandlerInternal	 */	@Override	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {		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 = getApplicationContext().getBean(handlerName);		}		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);		if (CorsUtils.isCorsRequest(request)) {			CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);		}		return executionChain;	} package org.springframework.web.servlet.handler; /**	 * Look up a handler for the URL path of the given request.	 * @param request current HTTP request	 * @return the handler instance, or {@code null} if none found	 */	@Override	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);//coffee/helloworld *** 往下看		Object handler = lookupHandler(lookupPath, request);		if (handler == null) {			// We need to care for the default handler directly, since we need to			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.			Object rawHandler = null;			if ("/".equals(lookupPath)) {				rawHandler = getRootHandler();			}			if (rawHandler == null) {				rawHandler = getDefaultHandler();			}			if (rawHandler != null) {				// Bean name or resolved handler?				if (rawHandler instanceof String) {					String handlerName = (String) rawHandler;					rawHandler = getApplicationContext().getBean(handlerName);				}				validateHandler(rawHandler, request);				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);			}		}		if (handler != null && logger.isDebugEnabled()) {			logger.debug("Mapping [" + lookupPath + "] to " + handler);		}		else if (handler == null && logger.isTraceEnabled()) {			logger.trace("No handler mapping found for [" + lookupPath + "]");		}		return handler;	} package org.springframework.web.util; class UrlPathHelper  public String getLookupPathForRequest(HttpServletRequest request) {        if(this.alwaysUseFullPath) {            return this.getPathWithinApplication(request);        } else {            String rest = this.getPathWithinServletMapping(request);//运行结果 --> ""            return !"".equals(rest)?rest:this.getPathWithinApplication(request);//执行getpathWithApplication 返回 /coffee/helloworld        }    } 上面的方法执行的是else public String getPathWithinServletMapping(HttpServletRequest request) {        String pathWithinApp = this.getPathWithinApplication(request);//coffee/helloworld  ******往下看        String servletPath = this.getServletPath(request);//coffee/helloworld  ******往下看        String sanitizedPathWithinApp = this.getSanitizedPath(pathWithinApp);        String path;        if(servletPath.contains(sanitizedPathWithinApp)) {            path = this.getRemainingPath(sanitizedPathWithinApp, servletPath, false); //结果 ""        } else {            path = this.getRemainingPath(pathWithinApp, servletPath, false);        }        if(path != null) {            return path; // 返回 ""        } else {            String pathInfo = request.getPathInfo();            if(pathInfo != null) {                return pathInfo;            } else {                if(!this.urlDecode) {                    path = this.getRemainingPath(this.decodeInternal(request, pathWithinApp), servletPath, false);                    if(path != null) {                        return pathWithinApp;                    }                }                return servletPath;            }        }    } public String getPathWithinApplication(HttpServletRequest request) {        String contextPath = this.getContextPath(request);// ""        String requestUri = this.getRequestUri(request);//coffee/helloworld        String path = this.getRemainingPath(requestUri, contextPath, true);//coffee/helloworld        return path != null?(StringUtils.hasText(path)?path:"/"):requestUri;//coffee/helloworld    }  public String getContextPath(HttpServletRequest request) {        String contextPath = (String)request.getAttribute("javax.servlet.include.context_path");        if(contextPath == null) {            contextPath = request.getContextPath();        }        if("/".equals(contextPath)) {///*****注意一下这个方法如果            contextPath = "";        }        return this.decodeRequestString(request, contextPath);    } public String getServletPath(HttpServletRequest request) {        String servletPath = (String)request.getAttribute("javax.servlet.include.servlet_path");        if(servletPath == null) {            servletPath = request.getServletPath();//*******/coffee/helloworld        }        if(servletPath.length() > 1 && servletPath.endsWith("/") && this.shouldRemoveTrailingServletPathSlash(request)) {            servletPath = servletPath.substring(0, servletPath.length() - 1);        }        return servletPath;    } /**	 * Look up a handler instance for the given URL path.	 * 

Supports direct matches, e.g. a registered "/test" matches "/test", * and various Ant-style pattern matches, e.g. a registered "/t*" matches * both "/test" and "/team". For details, see the AntPathMatcher class. *

Looks for the most exact pattern, where most exact is defined as * the longest path pattern. * @param urlPath URL the bean is mapped to * @param request current HTTP request (to expose the path within the mapping to) * @return the associated handler instance, or {@code null} if not found * @see #exposePathWithinMapping * @see org.springframework.util.AntPathMatcher */ protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // Direct match? *************************************下面一行代码是真正查询Controller的方法 Object handler = this.handlerMap.get(urlPath); if (handler != null) { // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } // Pattern match? List

matchingPatterns = new ArrayList
(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } else if (useTrailingSlashMatch()) { if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) { matchingPatterns.add(registeredPattern +"/"); } } } String bestPatternMatch = null; Comparator
patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); if (logger.isDebugEnabled()) { logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns); } bestPatternMatch = matchingPatterns.get(0); } if (bestPatternMatch != null) { handler = this.handlerMap.get(bestPatternMatch); if (handler == null) { Assert.isTrue(bestPatternMatch.endsWith("/")); handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1)); } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them Map
uriTemplateVariables = new LinkedHashMap
(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) { Map
vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map
decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } if (logger.isDebugEnabled()) { logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables); } return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }

 

转载地址:https://blog.csdn.net/id19870510/article/details/53098834 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:fiddler 配置、以及抓取app的报文
下一篇:用intellig IDEA开发 Spring MVC第一篇

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月13日 02时55分12秒