本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制。通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的。

1、用户请求处理过程:

1、用户发送请求时会先从DispathcherServler的doService方法开始,在该方法中会将ApplicationContext、localeResolver、themeResolver等对象添加到request中,紧接着就是调用doDispatch方法:

源码:

  1. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. if (logger.isDebugEnabled()) {
  3. String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
  4. logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
  5. " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  6. }
  7. // Keep a snapshot of the request attributes in case of an include,
  8. // to be able to restore the original attributes after the include.
  9. Map<String, Object> attributesSnapshot = null;
  10. if (WebUtils.isIncludeRequest(request)) {
  11. attributesSnapshot = new HashMap<String, Object>();
  12. Enumeration<?> attrNames = request.getAttributeNames();
  13. while (attrNames.hasMoreElements()) {
  14. String attrName = (String) attrNames.nextElement();
  15. if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
  16. attributesSnapshot.put(attrName, request.getAttribute(attrName));
  17. }
  18. }
  19. }
  20. // Make framework objects available to handlers and view objects.
  21. <strong>request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
  22. request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  23. request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  24. request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());</strong>
  25. FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
  26. if (inputFlashMap != null) {
  27. request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
  28. }
  29. request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
  30. request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
  31. try {
  32. <strong>doDispatch(request, response);</strong>
  33. }
  34. finally {
  35. if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  36. return;
  37. }
  38. // Restore the original attribute snapshot, in case of an include.
  39. if (attributesSnapshot != null) {
  40. restoreAttributesAfterInclude(request, attributesSnapshot);
  41. }
  42. }
  43. }

doDispatch方法就是处理用户请求的方法。

2、进入该方法后首先会检查该请求是否是文件上传的请求(校验的规则是是否是post并且contenttType是否为multipart/为前缀)即调用的是checkMultipart方法;如果是的将request包装成MultipartHttpServletRequest。见源码:

doDispatch:

  1. processedRequest = checkMultipart(request);

checkMultipart:

  1. protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
  2. if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
  3. if (request instanceof MultipartHttpServletRequest) {
  4. logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
  5. "this typically results from an additional MultipartFilter in web.xml");
  6. }
  7. else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) {
  8. logger.debug("Multipart resolution failed for current request before - " +
  9. "skipping re-resolution for undisturbed error rendering");
  10. }
  11. else {
  12. return this.multipartResolver.resolveMultipart(request);
  13. }
  14. }
  15. // If not returned before: return original request.
  16. return request;
  17. }

3、然后调用getHandler方法来匹配每个HandlerMapping对象,如果匹配成功会返回这个Handle的处理链HandlerExecutionChain对象,在获取该对象的内部其实也获取我们自定定义的拦截器,并执行了其中的方法

见源码:

doDispatch:

  1. HandlerExecutionChain mappedHandler = null;
  2. mappedHandler = getHandler(processedRequest);

getHandler方法:

  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. for (HandlerMapping hm : this.handlerMappings) {
  3. if (logger.isTraceEnabled()) {
  4. logger.trace(
  5. "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
  6. }
  7. HandlerExecutionChain handler = hm.getHandler(request);
  8. if (handler != null) {
  9. return handler;
  10. }
  11. }
  12. return null;
  13. }
  1. hm.getHandler方法:
  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. Object handler = getHandlerInternal(request);
  3. if (handler == null) {
  4. handler = getDefaultHandler();
  5. }
  6. if (handler == null) {
  7. return null;
  8. }
  9. // Bean name or resolved handler?
  10. if (handler instanceof String) {
  11. String handlerName = (String) handler;
  12. handler = getApplicationContext().getBean(handlerName);
  13. }
  14. return getHandlerExecutionChain(handler, request);
  15. }

getHandlerExecutionChain:

  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  2. HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
  3. (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
  4. chain.addInterceptors(getAdaptedInterceptors());
  5. String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
  6. for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
  7. if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
  8. chain.addInterceptor(mappedInterceptor.getInterceptor());
  9. }
  10. }
  11. return chain;
  12. }

4、执行拦截器的preHandle方法,如果返回false执行afterCompletion方法并理解返回

5、通过上述获取到了HandlerExecutionChain对象,通过该对象的getHandler()方法获得一个object通过HandlerAdapter进行封装得到HandlerAdapter对象

6、该对象调用handle方法来执行Controller中的方法,该对象如果返回一个ModelAndView给DispatcherServlet

7、DispatcherServlet借助ViewResolver完成逻辑试图名到真实视图对象的解析,得到View后DispatcherServlet使用这个View对ModelAndView中的模型数据进行视图渲染

本文转自:http://blog.csdn.net/liyantianmin/article/details/46948963

源码深度解析SpringMvc请求运行机制(转)的更多相关文章

  1. SpringMVC 源码深度解析&lt;context:component-scan&gt;(扫描和注冊的注解Bean)

    我们在SpringMVC开发项目中,有的用注解和XML配置Bean,这两种都各有自己的优势,数据源配置比較经经常使用XML配置.控制层依赖的service比較经经常使用注解等(在部署时比較不会改变的) ...

  2. Spring源码深度解析之Spring MVC

    Spring源码深度解析之Spring MVC Spring框架提供了构建Web应用程序的全功能MVC模块.通过策略接口,Spring框架是高度可配置的,而且支持多种视图技术,例如JavaServer ...

  3. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  4. 并发编程(十五)——定时器 ScheduledThreadPoolExecutor 实现原理与源码深度解析

    在上一篇线程池的文章<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中从ThreadPoolExecutor源码分析了其运行机制.限于篇幅,留下了Scheduled ...

  5. spring源码深度解析— IOC 之 容器的基本实现

    概述 上一篇我们搭建完Spring源码阅读环境,spring源码深度解析—Spring的整体架构和环境搭建 这篇我们开始真正的阅读Spring的源码,分析spring的源码之前我们先来简单回顾下spr ...

  6. Go netpoll I/O 多路复用构建原生网络模型之源码深度解析

    导言 Go 基于 I/O multiplexing 和 goroutine 构建了一个简洁而高性能的原生网络模型(基于 Go 的I/O 多路复用 netpoll),提供了 goroutine-per- ...

  7. Spring源码深度解析之事务

    Spring源码深度解析之事务 目录 一.JDBC方式下的事务使用示例 (1)创建数据表结构 (2)创建对应数据表的PO (3)创建表和实体之间的映射 (4)创建数据操作接口 (5)创建数据操作接口实 ...

  8. 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)

    在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...

  9. VueRouter 源码深度解析

    VueRouter 源码深度解析 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还 ...

随机推荐

  1. 一次我们网站的web性能优化

    1.Google的Web优化最佳实践 利用PageSpeed工具 对我们红酒世界网进行检测时,发现了下面的几个问题 1.Leverage browser caching 1.1.通过web.confi ...

  2. DataGridView控件

    DataGridView控件 DataGridView是用于Windows Froms 2.0的新网格控件.它可以取代先前版本中DataGrid控件,它易于使用并高度可定制,支持很多我们的用户需要的特 ...

  3. 查看Android应用签名信息

    本文档介绍在Android下如何查看自己的应用签名及三方APK或系统APK签名信息,包含其中的MD5.SHA1.SHA256值和签名算法等信息. 1.查看自己的应用签名 可以通过两种方式查看 (1)  ...

  4. ACK

    ACK (Acknowledgement),即确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符.表示发来的数据已确认接收无误. 目录 1基本介绍 2详细释义     1基本介绍编辑 英文缩 ...

  5. SASS学习笔记_02

    导入 当模块化布局的时候 导入头和尾 私有化 不生成css文件 文件名前面加下划线   结果   嵌套导入   导入css文件 不推荐   注释 和默认变量值

  6. 【BZOJ】【1552】【Cerc2007】robotic sort / 【3506】【CQOI2014】排序机械臂

    Splay 离散化+Splay维护序列…… 好吧主要说一下我做这道题遇到的几个错误点: 1.离散化 2.由于找到的这个数的位置一定是大于等于 i 的,所以其实在把它splay到根以后,i 结点只能sp ...

  7. cf 61E. Enemy is weak 树状数组求逆序数(WA) 分类: Brush Mode 2014-10-19 15:16 104人阅读 评论(0) 收藏

    #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> ...

  8. javascript遍历子元素

    最近写代码时需要获取符合某些条件的节点子元素,用firstChild之类的方法会包含文本节点,所以包装了一个简单的类: //子元素遍历器 function ElementWalker(node) { ...

  9. [工作积累] 32bit to 64bit: array index underflow

    先贴一段C++标准(ISO/IEC 14882:2003): 5.2.1 Subscripting: 1 A postfix expression followed by an expression ...

  10. 如何在PL/SQL Developer 中设置 在select时 显示所有的数据

    在执行select 时, 总是不显示所有的记录, 要点一下, 下面那个按钮才会显示所有的数据.     解决方法: Tools>Preferences>Window Types>SQ ...