首页 > 编程语言 >springmvc请求源码流程解析(二)

springmvc请求源码流程解析(二)

时间:2024-10-31 21:17:33浏览次数:3  
标签:调用 映射 springmvc DispatcherServlet 对象 源码 处理器 解析 方法

       Spring官网的MVC模块介绍:Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中。正式名称“Spring Web MVC”来自其源模块的名称(spring-webmvc),但它通常被称为SpringMVC。

       从Servlet到SpringMVC:
       最典型的MVC就是JSP + servlet + javabean的模式。传统Servlet:

        传统servlet的弊端:
        1.xml下配置servlet的映射非常麻烦开发效率低
        2.必须要继承父类、重写方法侵入性强
        3.参数解析麻烦:单个参数(转换类型)--->pojo对象,Json文本--->pojo对象
        4.数据响应麻烦:pojo对象--->json
        5.跳转页面麻烦, 对path的控制、设置编码麻烦...等等...

        所以SpringMVC 就是在Servlet的基础上进行了封装,帮我把这些麻烦事都给我们做了。

       SpringMVC的具体执行流程:

       Spring MVC 是围绕前端控制器模式设计的,其中中央 Servlet DispatcherServlet 为
请求处理流程提供统一调度,实际工作则交给可配置组件执行。

      具体组件作用

      DispatcherServlet:前端调度器,负责将请求拦截下来分发到各控制器方法中。
      HandlerMapping: 负责根据请求的URL和配置@RequestMapping映射去匹配, 匹配到会返回Handler(具体控制器的方法)。
      HandlerAdaper: 负责调用Handler具体的方法然后返回视图的名字,Handler将它封装到ModelAndView(封装视图名,request域的数据)。
      ViewReslover: 根据ModelAndView里面的视图名地址去找到具体的jsp封装在View对象中。
      View:进行视图渲染(将jsp转换成html内容,这是Servlet容器的事情了) ,最终response返回客户端。

       具体执行流程
      1. 用户发送请求至前端控制器DispatcherServlet。
      2. DispatcherServlet收到请求调用处理器映射器HandlerMapping。处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
      3. DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作。
      4. 执行处理器Handler(Controller,也叫页面控制器)。Handler执行完成返回ModelAndView,HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet。
      5. DispatcherServlet将ModelAndView传给ViewReslover视图解析器,ViewReslover解析后返回具体View。
      6. DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
      7. DispatcherServlet响应用户。

      整个调用过程其实都在doDispatch中体现了,用户发送请求至前端控制器DispatcherServlet,由于它是个Servlet所以tomcat接收到请求后,会先调用它的service方法-->doGet/doPost-->processRequestdoService--->doDispatch。


       1、mappedHandler = getHandler(processedRequest)

       DispatcherServlet收到请求调用处理器映射器HandlerMapping。处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain (包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。

       2、HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())

       DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter。

       3、mappedHandler.applyPreHandle(processedRequest, response))

       前置拦截器

       4、ha.handle(processedRequest, response, mappedHandler.getHandler())

       执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作。执行处理器Handler(Controller,也叫页面控制器),Handler执行完成返回ModelAndView,HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet。

       5、applyDefaultViewName(processedRequest, mv)

       如果没有视图,给你设置默认视图。

       6、mappedHandler.applyPostHandle(processedRequest, response, mv)

       后置拦截器

       HandlerMapping

       在整个过程中,涉及到非常多的组件,每个组件解析各个环节,其中HandlerMapping最为重要它是用来映射请求的,我们就着重介绍下HandlerMapping的解析过程和请求映射过程。                     HandlerMapping在请求之前会建立映射关系,在HandlerMapping类实例化的时候就会完成url 和method的映射关系,要根据一个请求能够唯一找到一个类和一个方法。

       由于实际开发过程中RequestMappingHandlerMapping的使用最多,所以我们先看它的实例化,在其父类AbstractHandlerMethodMapping 中实现了InitializingBean 接口,所以在
RequestMappingHandlerMapping 实例化完成以后就会调用到afterPropertiesSet 方法,在这个方法里面完成了映射关系的建立。

       这里判断类上面是否有@Controller注解或@RequestMapping注解,只有这种类才需要建立映射关系,如果类上面有这两个注解,就在detectHandlerMethods方法中建立uri和method的映射关系,这个方法很重要。

1、ReflectionUtils.doWithMethods中循环Controller类里面的所有method方法,执行MethodFilter.doWith方法。

2、那么每个MethodFilter.doWith方法调用都会执行到外面的方法体,T result = metadataLookup.inspect(specificMethod),然后这行方法又会执行到外面的方法体,也就是会执行到getMappingForMethod(method, userType)方法。它会收集方法上面的@RequestMapping注解,把注解里面的配置信息封装到类里面,该类就是RequestMappingInfo类,并且跟类上面的@RequestMapping注解封装类RequestMappingInfo 合并,比如类上面是/common,方法上面是/queryUser。这两者合并后就是/common/queryUser,这样的url 才是我们需要的,合并完就是这样的url。

3、然后建立method 对象和对应的RequestMappingInfo 的映射关系,把关系存放到map 中。

4、然后回对map进行处理,执行registerHandlerMethod方法

5、createHandlerMethod这里会创建HandlerMethod 对象,该类型封装了method、beanName、bean、方法类型等信息。然后this.mappingLookup.put(mapping, handlerMethod)建立RequestMappingInfo 和HandlerMethod 的映射关系。this.urlLookup.add(url, mapping)建立url 和RequestMappingInfo 对象的映射关系。这样映射关系就已经建立好,这样根据请求url 我们就可以唯一的找到一个HandlerMethod 对象了,注意这个对象中还不能进行反射调用,还缺少参数数组。

        dispatcherServlet 处理请求

        当请求过来时,首先会调用到service 方法,最终会调用到dispatcherServlet 中的doDispatch 方法。根据请求url 获取HandlerExecutionChain 对象,寻找HandlerMethod 的过程由于前面映射关系已经建立好了,现在就是只需要从request 对象中获取请求url,然后从映射关系中获取HandlerMethod 对象就可以了,先从urlLookup中获取RequestMappingInfo 对象,然后再根据RequestMappingInfo对象获取到HandlerMethod。

       获取到HandlerMethod 对象后,就把HandlerMethod 对象封装到HandlerExecutionChain 对象中了,这个对象,其实就是封装了HandlerMethod 和一个拦截器数组而已。

       拿到HandlerExecutionChain 对象进行过滤器的调用,调用了前置过滤器preHandle 方法,只要这个方法返回为false,则后续请求就不会继续。

       然后是HandlerAdapter调用handle方法,进行具体Controller 中方法的调用这个调用过程,关键点就在于参数的解析,其他都没什么技术含量。

       首先获取方法的参数列表,并且把参数封装成MethodParameter 对象,这个对象记录了
参数在参数列表中的索引,参数类型,参数上面的注解数组等等信息。然后循环参数列表,一个个参数来处理,这里是一个典型的策略模式的运用,根据参数获取一个处理该参数的类,把参数一个个处理完成后,放到一个参数数组中了Object[] args。

        处理参数的解析类有26 个,如图:

       接下来就是反射调用了,有方法method 对象,有类对象,有参数数组就可以进行反射调用了。

        返回值处理

       当反射调用成功后,有可能方法会有返回值,而返回值处理也是一个比较重要的事情,根据
什么样的方式把返回值响应回去,返回值响应时有可能是数据有可能是界面,而如果返回数据的
话,要把返回值解析成对应的格式,例如如果返回值是一个list 对象,就需要解析这个list对象把list 对象解析成json 格式。返回值解析讨论跟入参解析基本上类似。
1、把返回值封装成对象,对象跟MethodParameter 对象差不多,里面包括参数名称、类型、参数注解等等信息。
2、根据返回值类型用策略模式找到一个解析类,然后用这个解析类解析。
4、一个是带@ResponseBody 注解的,一个是直接返回字符串响应一个界面的,里面涉及到一个ModelAndViewContainer 容器,这个容器会把视图名称设置到里面,而且会把响应到界面的数据也会放到这个容器中。

       后置过滤器的调用时序,是当ha.handle 掉完以后,也就是Controller 里面具体方法调用完以后才轮到后置过滤器调用。

       视图渲染

       其实就是响应界面,如果返回值没有加@ResponseBody 注解时,这时候是需要响应一个界面给前端的,视图渲染借助了servlet 中的api,如下图这样servlet 就可以响应一个界面给前端,而我们spring 也是差不多的处理方式。

       异常解析
      Controller 调用过程中的异常解析使用,如图:


       类上面加上@ControllerAdvice("com.dsk")注解,这个包定义就是只对这个包里面的Controller 生效。然后类里面的方法加上@ExceptionHandler({ArrayIndexOutOfBoundsException.class})
@ExceptionHandler({NullPointerException.class})表示这个方法当调用过程中出现注解里面定义的异常时会被调用到,这些方法就是对异常处理的方法。

      源码的核心思想差不多
     1、收集注解包装成类
     2、建立@ExceptionHandler 中异常和Method 的映射关系
     3、根据出现的异常从映射关系中找到对应的Method 对象
     4、反射调用,这个调用逻辑跟Controller 里面具体方法调用逻辑一模一样

标签:调用,映射,springmvc,DispatcherServlet,对象,源码,处理器,解析,方法
From: https://blog.csdn.net/qq_40228720/article/details/143276223

相关文章

  • 全面解析云渲染:定义、优势、分类与发展历程
    随着数字时代的到来,云计算成为了信息技术领域不可或缺的一部分,其核心在于允许用户通过互联网访问并利用远程计算资源。云渲染作为云计算的一种应用,将3D图形和动画的渲染任务交由云端的服务器集群处理,从而彻底改变了传统渲染的方式,并为3D创作注入了新的活力。一、云渲染简介云渲......
  • SpringBoot社区养老综合服务平台g57pn--程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,志愿者,工作人员,社区展示,费用缴纳,房间信息,请假信息,志愿者分配,志愿者任务,工作人员任务,任务完成,工资绩效开题报告内容一、研究背景随着人口老龄化......
  • SpringBoot社区老人颐养关爱平台05161(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,活动类型,社区活动,志愿活动,健康申报,健康建议,活动报名开题报告内容一、项目名称社区老人颐养关爱平台设计与实现二、研究背景与意义随着老龄化社会......
  • 基于SpringBoot+Vue+uniapp的宿舍管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的物流信息管理系统的详细设计和实现(源码+lw+部署文档+讲
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • SpringBoot社区图书管理系统681x1(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,图书分类,图书信息,图书借阅,还书登记,捐赠项目,物资捐赠开题报告内容一、研究背景与意义随着信息化时代的到来,图书馆管理系统已被广泛应用于各类单位,包......
  • SpringBoot社区健康网站8gg2e(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,安全宣传,社区活动,活动报名开题报告内容一、研究背景与意义随着互联网的普及和居民健康意识的增强,传统的健康信息传播方式已难以满足现代人的需求。社区......
  • (开题报告)django+vue高校OA系统论文+源码
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于高校OA系统的研究,现有研究主要集中在传统开发技术或单一功能模块的优化上。在国内外,虽然OA系统已广泛应用于企业等领域,但专门针对......
  • SERVLET程序设计2554停车场计费系统设计与实现源码
    项目包含:源码、论文、讲解视频、说明文档请查看博主个人简介运行环境:推荐jdk1.8开发工具:Eclipse、MyEclipe以及idea(推荐)操作系统:windows108G内存以上(其他windows)浏览器:GoogleChrome(推荐)、Edge、360浏览器;数据库:MySQL5.7;数据库可视化工具:NavicatPremium推荐)以......
  • SpringBoot社区疫情防控系统的设计与实现66u82程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表居民,确诊人员,外来人员报备,健康上报,商品分类,防疫物品开题报告内容一、研究背景随着全球疫情的持续影响,社区疫情防控已成为保障居民健康安全的重要防线。传......