转自:http://blog.csdn.net/shi1122/article/details/8041017

(转移位置了,时光隧道:http://www.jmatrix.org/spring/501.html

在之前的“spring MVC实现分析——初始化”中分析了spring mvc的初始化过程,接下来将分析其请求处理过程。

在找请求处理的入口时,我们需要先知道Servlet的编程规范,对应不同的请求(如POST、GET等)的实现方法在FrameworkServlet 中,分别是doPost、doGet等,看这一系列方法的具体实现可以知道,请求的处理跳转到了processRequest函数中,最终进入 DispatcherServlet的doService函数,详细的流程如:

上面的时序图展示了详细的请求处理流程,其中最重要的是doDispatch函数,其中包含了整个的处理逻辑,

  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. HttpServletRequest processedRequest = request;
  3. HandlerExecutionChain mappedHandler = null;
  4. boolean multipartRequestParsed = false;
  5. WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
  6. try {
  7. ModelAndView mv = null;
  8. Exception dispatchException = null;
  9. try {
  10. processedRequest = checkMultipart(request);
  11. multipartRequestParsed = processedRequest != request;
  12. // Determine handler for the current request.
  13. mappedHandler = getHandler(processedRequest, false);
  14. if (mappedHandler == null || mappedHandler.getHandler() == null) {
  15. noHandlerFound(processedRequest, response);
  16. return;
  17. }
  18. // Determine handler adapter for the current request.
  19. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  20. // Process last-modified header, if supported by the handler.
  21. ……
  22. try {
  23. // Actually invoke the handler.
  24. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  25. }
  26. finally {
  27. if (asyncManager.isConcurrentHandlingStarted()) {
  28. return;
  29. }
  30. }
  31. applyDefaultViewName(request, mv);
  32. mappedHandler.applyPostHandle(processedRequest, response, mv);
  33. }
  34. catch (Exception ex) {
  35. dispatchException = ex;
  36. }
  37. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  38. }
  39. ……
  40. }
  41. finally {
  42. ……
  43. }
  44. }

首先我们先看HandlerExecutionChain这个类中有些什么东西,

  1. public class HandlerExecutionChain {
  2. private final Object handler;
  3. private HandlerInterceptor[] interceptors;
  4. private List<HandlerInterceptor> interceptorList;
  5. ……
  6. }

这里面有两个关键的东西handler与interceptors,也即处理器对象与拦截器链表,联系到我们实际的编程,handler有可能是两种东
西:(1)controller类对象;(2)controller中的方法对象(用的术语可能不太准确……)。而interceptors也即我们定义
拦截器对象列表,如果说想在请求被处理之前做点什么就会弄一个。明白了这一点,再来看看在doDispatch函数中如果获得
HandlerExecutionChain对象mappedHandler。

可以看到其实现在getHandler方法中:

  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. for (HandlerMapping hm : this.handlerMappings) {
  3. ……
  4. HandlerExecutionChain handler = hm.getHandler(request);
  5. if (handler != null) {
  6. return handler;
  7. }
  8. }
  9. return null;
  10. }

函数的实现非常简单:遍历已注册的HandlerMapping列表,通过HandlerMapping对象的getHandler函数获取
HandlerExecutionChain对象。至于HandlerMapping中的getHandler函数如何获取
HandlerExecutionChain需要的处理器与拦截器,我只能说过程是繁琐的,原理是简单的,对于处理器对象(handler)根据不同的
Mapping实现,其可以根据bean配置中的urlPath或者是方法的注解来寻找,这里不再细说。

顺着doDispatch函数的执行流程往下看,紧接着其通过getHandlerAdapter函数获得HandlerAdapter对象ha,然后就是又要重点照顾的一个调用:

  1. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

随着调用HandlerAdapter的handle函数,Spring
MVC便开始要真的“干实事”了,所谓的“干实事”也即开始调用执行我们编写的controller(控制逻辑)了。这里以两个
HandlerAdapter的实现HttpRequestHandlerAdapter与
AnnotationMethodHandlerAdapter来分析这个处理流程,在之前的一篇文章“Spring
MVC实现分析——初始化过程
”中有提到我自己的一个Spring MVC程序配置,以此为准进行展开:

HttpRequestHandlerAdapter的实现是最容易理解的,因为其handle的实现就是调用了处理器(handler)对象的
handleRequest函数,借助F4看看Controller的继承体系,再看看AbstractController中
handleRequest函数的实现,结合自己菜鸟时期编写的Spring MVC “hello world程序”,你就会有恍然大悟的感觉⊙﹏⊙!

至于AnnotationMethodHandlerAdapter,其实现原理也是很容易理解的,我们已经知道其就是针对采用注解方式的方法映射的,实际应用中如:

  1. @RequestMapping(method=RequestMethod.GET,value="/homeController.xhtml")
  2. protected ModelAndView handleRequestInternal(HttpServletRequest arg0,
  3. HttpServletResponse arg1) throws Exception {
  4. ……
  5. }

所以其handle的实现就是通过Java的反射机制找到注解对应的处理方法,并调用完成控制逻辑的执行。

此时,让我们再次回到doDispatch的处理流程上来,在经过handle的“干实事”后,我们得到了ModelAndView对象,也即视图对象,
很自然接下来的就是视图的渲染与展示了,这也是我们最后要分析的一个点。其入口是doDispatch中的一个函数调用:

    1. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

Spring MVC源码分析(续)——请求处理的更多相关文章

  1. 精尽Spring MVC源码分析 - 寻找遗失的 web.xml

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  2. 精尽Spring MVC源码分析 - 调式环境搭建

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  3. 精尽Spring MVC源码分析 - 文章导读

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  4. 精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  5. 精尽Spring MVC源码分析 - 一个请求的旅行过程

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  6. 精尽Spring MVC源码分析 - MultipartResolver 组件

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  7. 精尽Spring MVC源码分析 - HandlerMapping 组件(一)之 AbstractHandlerMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  8. 精尽Spring MVC源码分析 - HandlerMapping 组件(二)之 HandlerInterceptor 拦截器

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  9. 精尽Spring MVC源码分析 - HandlerMapping 组件(三)之 AbstractHandlerMethodMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  10. 精尽Spring MVC源码分析 - HandlerMapping 组件(四)之 AbstractUrlHandlerMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

随机推荐

  1. Android解析qq聊天记录表情

    偶然在一个需求中需要解析qq聊天记录表情,表情的格式是以/开始,比如:你好啊?/微笑,在网上找了半天,也没能找到一个比较合适的,所以准备自己实现一下,首先要将表情图片和表情字符对上号,我想了几种解决方 ...

  2. [置顶] 如何访问web文件夹之外的文件

        在编写项目时,遇到一个如何访问web文件夹之外的文件的问题.因为我要制作一个浏览图片和pdf文件的一个简单网站.但问题是图片的文件夹和pdf文件的文件夹都是其他程序生成的,自然也就是不是网站w ...

  3. 修改Unity脚本模板的方法合计

    作为一个习惯于偷懒的程序,重复性的无聊内容是最让人无奈的事,就比如我们创建Unity脚本之后,需要手动调整生成的新脚本的格式.编码.内容:如果我们要编写的是编辑器或者服务器端脚本,需要修改的内容就会更 ...

  4. 英文Ubantu系统安装中文输入法

    以前都是安装的中文Ubantu,但是有时候用命令行的时候中文识别不好,会出现错误,所以这次安装了英文版,但是安装后发现输入法不好用,于是就要自己安装输入法. 安装环境为Ubantu13.04 1.卸载 ...

  5. docker-proxy 实现容器代理访问

    可实现多个容器web主机对外提供访问 运行代理容器 nginx-proxy docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.soc ...

  6. [Webpack 2] Grouping vendor files with the Webpack CommonsChunkPlugin

    Often, you have dependencies which you rarely change. In these cases, you can leverage the CommonsCh ...

  7. JAVA中toString方法的作用(转)

    因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”. 它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不 ...

  8. mysql 超时设置

      在Mysql的默认设置中,如果一个数据库连接超过8小时没有使用(闲置8小时,即   28800s),mysql server将主动断开这条连接,后续在该连接上进行的查询操作都将失败,将   出现: ...

  9. PS软件之,快速的修改图片你的尺寸

    进入 -- 图像 --- 图像尺寸 -- (前面两个去掉后,只剩下最后一个选项的时候就能够任意的修改图像的尺寸)

  10. C++的MFC,与C#的.NET

    转载:http://blog.sina.com.cn/s/blog_7f5bde5c0101hk5n.html 以下摘自各问答网站.博客论坛: [1]MFC早已过时,现在C++多数是用来编写底层方法而 ...