本文依赖的是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. cocos2dx 2.0+ 版本,IOS6.0+设置横屏

    使用cocos2dx 自带的xcode模板,是不能正常的设置为横屏的. 一共修改了三个地方: 在项目属性中:Deployment Info中,勾选上 Landscape left,以及 Landsca ...

  2. 在Eclipse中制作SSH配置文件提示插件

    原文地址:http://blog.csdn.net/longyuhome/article/details/8968093 这篇博客算是对原先的“在Eclipse中制作和使用struts2配置文件提示插 ...

  3. linux下搭建mysql主从

    在master上创建repl账户,用于复制. grant replication slave on *.* to 'repl'@'%' identified by 'P@$$W0rd'; flush ...

  4. javascript各种模式解析

    1.工厂模式: 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创建 ...

  5. 搭建SpringMVC+MyBatis开发框架二

    配置web.xml 用如下配置覆盖原有的web.xml内容 <?xml version="1.0" encoding="UTF-8"?> <w ...

  6. Careercup - Google面试题 - 5085331422445568

    2014-05-08 23:45 题目链接 原题: How would you use Dijkstra's algorithm to solve travel salesman problem, w ...

  7. android 自动化压力测试-monkey 2 获取程序包名

    monkey 1 中我们写到: C:\Users\chenshan>adb shell shell@hwG750-T20:/ $ monkey -p cn.emoney.acg -v 500 说 ...

  8. linux 操作

    正在运行的内核和系统信息 # uname -a # 获取内核版本(和BSD版本) # lsb_release -a # 显示任何 LSB 发行版版本信息 # cat /etc/SuSE-release ...

  9. Ext.Ajax中scope的作用

    在Ext的前台Js中使用Ajax请求,如果想让回调函数中的this作用域跟当前的类一样如何实现呢?Ajax提供了一个参数scope. 详细代码如下: layout : { type : 'accord ...

  10. EF 更新条目时出错。有关详细信息,请参见内部异常。

    现象:使用EF新增记录时,一直报上述异常,网上说是值为空.主键外键未设等原因导致,但是改正这些情况下问题依然 解决过程:异常中有一句(请参见内部异常),一直都没有当回事,后来实在没办法就静下心来看了看 ...