学习资料:开涛的《跟我学SpringMVC.pdf》

  众所周知,springMVC是比较常用的web框架,通常整合spring使用。这里抛开spring,单纯的对springMVC做一下总结。

  概念

  HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象)

  HandlerAdapter:处理器适配器,适配不同类型的处理器,如Controller、AbstractController等

  Handler:处理器,即开发的Controller

  ModeAndView:模型和视图,未来会渲染为具体的视图

  ViewResolver:视图解析器,将逻辑视图名称转化为物理视图

  View:视图

  流程图

  源码简析(摘自DispatcherServlet源码部分)

  由于springMVC的配置本身就上一个servlet,所以跟踪代码doService()=>doDispatcher(),核心代码如下所示,中文注释自己加的

  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. HttpServletRequest processedRequest = request;
  3. HandlerExecutionChain mappedHandler = null;
  4. boolean multipartRequestParsed = false;
  5.  
  6. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  7.  
  8. try {
  9. ModelAndView mv = null;
  10. Exception dispatchException = null;
  11.  
  12. try {
  13. //对文件上传类型的数据进行处理,使用MultipartResolver解析
  14. processedRequest = checkMultipart(request);
  15. multipartRequestParsed = (processedRequest != request);
  16.  
  17. //使用HandlerMapping进行映射,将一个Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象
  18. mappedHandler = getHandler(processedRequest);
  19. if (mappedHandler == null || mappedHandler.getHandler() == null) {
  20. noHandlerFound(processedRequest, response);
  21. return;
  22. }
  23.  
  24. //根据Handler获取合适的Handler适配器
  25. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  26.  
  27. // Process last-modified header, if supported by the handler.
  28. String method = request.getMethod();
  29. boolean isGet = "GET".equals(method);
  30. if (isGet || "HEAD".equals(method)) {
  31. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  32. if (logger.isDebugEnabled()) {
  33. logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
  34. }
  35. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  36. return;
  37. }
  38. }
  39.  
  40. /*
  41. * 调用拦截器的preHandle(),返回true继续执行下一个拦截器或处理器,返回false中断流程并执行执行成功的拦截器的afterCompletion()。
  42.           */
  43. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  44. return;
  45. }
  46.  
  47. //使用HandlerAdapter执行Handler并返回ModeAndView
  48. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  49.  
  50. if (asyncManager.isConcurrentHandlingStarted()) {
  51. return;
  52. }
  53.  
  54. applyDefaultViewName(processedRequest, mv);
  55. //调用拦截器的postHandle()方法
  56. mappedHandler.applyPostHandle(processedRequest, response, mv);
  57. }
  58. catch (Exception ex) {
  59. dispatchException = ex;
  60. }
  61. catch (Throwable err) {
  62. // As of 4.3, we're processing Errors thrown from handler methods as well,
  63. // making them available for @ExceptionHandler methods and other scenarios.
  64. dispatchException = new NestedServletException("Handler dispatch failed", err);
  65. }
  66. //处理转发结果,包含ModeAndView的视图解析,视图解析后调用拦截器的afterCompletion()函数
  67. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  68. }
  69. catch (Exception ex) {
  70. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  71. }
  72. catch (Throwable err) {
  73. triggerAfterCompletion(processedRequest, response, mappedHandler,
  74. new NestedServletException("Handler processing failed", err));
  75. }
  76. finally {
  77. if (asyncManager.isConcurrentHandlingStarted()) {
  78. // Instead of postHandle and afterCompletion
  79. if (mappedHandler != null) {
  80. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  81. }
  82. }
  83. else {
  84. // Clean up any resources used by a multipart request.
  85. if (multipartRequestParsed) {
  86. cleanupMultipart(processedRequest);
  87. }
  88. }
  89. }
  90. }

SpringMVC学习(一)——概念、流程图、源码简析的更多相关文章

  1. Flink源码阅读(一)——Flink on Yarn的Per-job模式源码简析

    一.前言 个人感觉学习Flink其实最不应该错过的博文是Flink社区的博文系列,里面的文章是不会让人失望的.强烈安利:https://ververica.cn/developers-resource ...

  2. django-jwt token校验源码简析

    一. jwt token校验源码简析 1.1 前言 之前使用jwt签发了token,里面的头部包含了加密的方式.是否有签名等,而载荷中包含用户名.用户主键.过期时间等信息,最后的签名还使用了摘要算法进 ...

  3. 0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

    1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日 ...

  4. spring ioc源码简析

    ClassPathXmlApplicationContext 首先我们先从平时启动spring常用的ClassPathXmlApplicationContext开始解析 ApplicationCont ...

  5. AFNetworking源码简析

    AFNetworking基本是苹果开发中网络请求库的标配,它是一个轻量级的网络库,专门针对iOS和OS X的网络应用设计,具有模块化的架构和丰富的APIs接口,功能强大并且使用简单,深受苹果应用开发人 ...

  6. OpenStack之Glance源码简析

    Glance简介 OpenStack镜像服务器是一套虚拟机镜像发现.注册.检索. glance架构图: Glance源码结构: glance/api:主要负责接收响应镜像管理命令的Restful请求, ...

  7. ElementUI 源码简析——源码结构篇

    ElementUI 作为当前运用的最广的 Vue PC 端组件库,很多 Vue 组件库的架构都是参照 ElementUI 做的.作为一个有梦想的前端(咸鱼),当然需要好好学习一番这套比较成熟的架构. ...

  8. 源码简析XXL-JOB的注册和执行过程

    一,前言 XXL-JOB是一个优秀的国产开源分布式任务调度平台,他有着自己的一套调度注册中心,提供了丰富的调度和阻塞策略等,这些都是可视化的操作,使用起来十分方便. 由于是国产的,所以上手还是比较快的 ...

  9. DRF之APIView源码简析

    一. 安装djangorestframework 安装的方式有以下三种,注意,模块就叫djangorestframework. 方式一:pip3 install djangorestframework ...

随机推荐

  1. Shiro源码解析-登录篇

    本文以循序渐进的方式解析Shiro整个login过程的处理,读者可以边阅读本文边自己看代码来思考体会,如有问题,欢迎评论区探讨! 笔者shiro的demo源码路径:https://github.com ...

  2. input 标签只能输入数字

    $("input[name='contact']").keyup(function(){ $("input[name='contact']").attr(&qu ...

  3. plsql起别名出现???乱码,需要配置环境变量

    NLS_LANG:SIMPLIFIED CHINESE_CHINA.ZHS16GBK

  4. thinkphp5+nginx的linux环境搭建

    安装环境&工具安装php安装nginx运行服务器安装thinkphp安装Composer安装thinkphp配置nginx.conf配置php-fpm运行thinkphp注意事项 php7已经 ...

  5. Ubuntu 18.04 安装 odoo12 源码版

    更新和升级 在我们进入安装过程之前,你应该更新和升级Ubuntu.打开终端窗口,发出以下命令: sudo apt-get updatesudo apt-get upgrade 注意:如果内核升级,则必 ...

  6. 仿jQuery的toggle方法

    两次点击事件进行切换 var toggle = (function () { var a = true; return function (fn1, fn2) { a = !a; var toggle ...

  7. selenium+Python(文件下载)

    webdriver允许我们设置默认的文件下载路径,也就是说,文件会自动下载并保存到设置的目录中 下面以Firefox浏览器为例: from selenium import webdriver from ...

  8. JDBC(1)-连接数据库

    主要步骤包括: 加载驱动: 连接数据库: 使用语句操作数据库: 关闭数据库连接,释放资源. 1.需要导包: 2.加载数据驱动: mysql驱动名:com.mysql.jdbc.Driver 加载方式: ...

  9. cut、grep和排序命令

    1.cut 对于行进行操作 cut -d ':' -f 2 以':'为分隔符,切出第二部分的所有行 cut -c 12- 从第12字符往后的字符所有行 2.grep grep '选取的串' 选出所有含 ...

  10. requirejs和seajs使用感受

    这几天看了下前端模块化的知识,主要是requirejs和seajs相关的知识,还未看es6的模块化知识. 由于目前项目组内的开始推广使用vue,并且开始简单的封装组件,但发现组件js的使用方式依然是原 ...