Spring MVC原理(二)请求处理流程源码分析
来源:互联网 发布:网络管理书籍推荐 编辑:程序博客网 时间:2024/06/05 20:56
请求的大概处理流程请参考这篇文章,这里摘来一张图。
http://www.jianshu.com/p/85a30095245e
DispatcherServlet作为流程控制的中心,整个请求的处理都是围绕这个servlet来进行。由名称可以看出这是一个servlet,具备普通servlet的所有的性质,既然是servlet肯定要在web.xml中配置,具体配置参考上面的文章。下面直接分析源码:
一个请求过来,只要是符合DispatcherServlet的拦截规则,web容器就会调用其doGet/doPost方法。
DispatcherServlet的继承体系和处理时序如下图所示:
DispatcherServlet的doGet/doPost方法的实现在其父类FrameworkServlet里面,
/** * 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); } /** * Delegate POST requests to {@link #processRequest}. * @see #doService */ @Override protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
这里以Get方法为例分析整个处理过程:
(源码中省略了一些注释或者不重要的片段)
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的实现在DispatchServlet中 doService(request, response); } 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(); } publishRequestHandledEvent(request, response, startTime, failureCause); } }
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { // 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<String, Object>(); 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); } } } }
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); // Determine handler for the current request. // 根据当前请求查找合适的处理器Handler 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(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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); } } } }
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { /* * HandlerMapping的作用是找到URL匹配的Handler对象,这里注册的HandlerMapping(handlerMappings中的元素)有三个: * 1)BeanNameUrlHandlerMapping: bean的name和url匹配 * 要求任何有可能处理请求的Bean都要起一个以反斜杠(/)字符开头的名称或者别名,这个名称或者别名可以是符合URL Path匹配原则中的任何名字。 * 它不能影射一个Prototype的Bean.换句话说,当使用 BeanNameUrlHandlerMapping时,所有的请求处理类只能是单例的(singletons) . 一般来 * 说,Controllers 都是按照单例建立的,所以这个并不是一个很严重的问题。 * 2)SimpleUrlHandlerMapping :直接匹配url和对应的bean(在mvc配置文件中配置,url和bean一一对应) * 由于BeanNameUrlHandlerMapping机制中URL和Handler是绑定在一起的,所以无法配置更为复杂的Mapping关系,SimpleUrlHandlerMapping * 可以看做是其的高级版,能够配置复杂的路径匹配关系,可以配置多组映射关系,把不同的URL映射到同一个handler对象。 * 3)RequestMappingHandlerMapping:专门处理注解@RequestMapping配置的类,和RequestMappingHandlerAdapter 对应起来使用 */ for (HandlerMapping hm : this.handlerMappings) { /* * 遍历所有的HandlerMapping,找到能够处理当前request的一个 */ HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
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); } return getHandlerExecutionChain(handler, request); }
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //拿到请求的url String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } //根据请求的路径URL找到对应的处理方法(controller里的方法) HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); if (logger.isDebugEnabled()) { if (handlerMethod != null) { logger.debug("Returning handler method [" + handlerMethod + "]"); } else { logger.debug("Did not find handler method for [" + lookupPath + "]"); } } return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); }
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); /* * this.urlMap放的是当前这个HandlerMapping对象类型处理的URL和handler * 在Spring容器启动阶段,就已经把mvc配置文件或者controller类注解的映射关系添加到了 * urlMap里面,以匹配的URL作为键值。 */ List<T> directPathMatches = this.urlMap.get(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.handlerMethods.keySet(), matches, request); } if (!matches.isEmpty()) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); Match bestMatch = matches.get(0); if (matches.size() > 1) { Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException( "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(handlerMethods.keySet(), lookupPath, request); } }
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { /* * HandlerAdapter的作用是确定Handler对象中的哪个方法来处理当前URL,这里注册的HandlerAdapter有三种: * 1)HttpRequestHandlerAdapter:要求handler(controller)实现HttpRequestHandler接口 * 2)SimpleControllerHandlerAdapter:要求handler实现Controller接口 * 3)RequestMappingHandlerAdapter:和RequestMappingHandlerMapping配对使用,专门处理@RequestMapping 注解的类和方法 */ for (HandlerAdapter ha : this.handlerAdapters) { if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
1 0
- Spring MVC原理(二)请求处理流程源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC请求处理流程及源码分析
- Spring MVC源码分析(续)——请求处理
- Spring MVC源码分析(续)——请求处理
- Spring MVC源码分析(续)——请求处理
- Spring MVC (DispatcherServlet)请求处理流程
- Spring MVC 处理请求流程
- spring mvc请求处理流程
- Spring MVC请求处理流程
- Spring MVC 处理请求流程
- Spring MVC请求处理流程
- Spring MVC请求处理流程
- sql server 遇到以零作除数错误。
- JavaScript、ES5、ES6有什么
- BottomSheetDialog的使用
- java画图总结之三(常用方法paint,repaint,update)
- jQuery datatable中加入双击跳转功能
- Spring MVC原理(二)请求处理流程源码分析
- IP地址、子网掩码、网络号、主机号、网络地址、主机地址
- mysql中的左连接、内连接、右连接和全连接理解
- a
- A20 camera预览图像正常,拍照图像变灰蓝
- LintCode 480:Binary Tree Paths
- FastDFS使用小结(单节点部署和集群部署)
- spi_device和spi_driver的匹配
- tshark命令示例