SpringMVC源码分析之——处理请求核心流程之controller_method的调用

DispatchServlet处理请求核心流程:

1. getHandler(processedRequest) 获取具体要执行的HandlerExecutionChain
2. getHandlerAdapter 获取处理适配器
3. mappedHandler.applyPreHandle 调用前置拦截器
4. 执行controller.method方法
5. mappedHandler.applyPostHandle 调用中置拦截器
6. processDispatchResult 视图的渲染
7. 调用后置拦截器

上一篇讲到getHandler(processedRequest)方法返回了一个HandlerExecutionChain对象,里面包含了HandleMethod对象和拦截器链,接下来DispatchServlet是如何调用我们写在controller中的业务方法的,拦截器的话后续统一讲

主要流程

1. 获取HandlerAdapter对象
2. 在前置拦截器调用完之后
   调用controller的方法
    2.1. @ModelAttribute方法的调用,返回值存放在mavc对象中
    2.2. ServletInvocableHandlerMethod初始化:有所有参数解析器和返回值解析器
    2.3. 参数解析
    2.4. 反射执行方法
    2.5. 返回值处理 
    2.6. 返回ModelAndView

源码分析:

1.HandlerAdapter的获取

在第二篇文章讲到,HandlerAdapter组件WebMvcConfigurationSupport用@bean的方式注册到了spring容器中,而DispatchServlet在servlet生命周期的init()方法中从spring容器取出HandlerAdapter类型的对象赋给了他的成员变量handlerAdapters。

接下来就是从handlerAdapters中找出匹配当前方法的handlerAdapter

image

这里有三个HandleAdapter,源码中使用策略模式,在每个HandleAdapter中都定义了自己对HandleMethod的支持策略

image

比如HttpRequestHandlerAdapter

image

这样在主线代码中,可以消除大量的if_else类型判断语句,以及契合了开闭原则。后续有需要增加的HandlerAdapter类型,只需要在类中同样的增加supports提供支持策略,而不用修改主线代码.

最终这里支持当前HandleMethod的ha适配器是

RequestMappingHandlerAdapter,并返回

image

2.controller方法的调用

之前讲到反射执行方法的必需的controller方法对象和controller的bean对象已经存在于HandlerExecutionChain的HandleMethod中了,

接下来就是用ha适配器传入HandlerExecutionChain的HandleMethod进行业务方法的调用

并且同样需要传入request对象,因为需要讲request中的参数与method的参数绑定起来

image

 点到RequestMappingHandlerAdapter对该方法的实现中

image

2.1. @ModelAttribute方法的调用,返回值存放在mavc对象中

当某一个controller方法上有@ModelAttribute注解时,可以被其他请求方法用@ModelAttribute 调用它一次,并把他的返回值结果传入其他请求方法

image

image

  1. 收集被请求方法@ModelAttribute调用的方法的HandleMethod对象,封装到了ModelFactory对象中

    image

  2. 调用有@ModelAttribute注解的方法

    image

    image

    调用之后把返回值放到ModelAndViewContainer对象中

    image

    后续,请求方法,会从这个容器中拿值赋给方法的参数

    2.2 SrvletInvocableHandlerMethod初始化:有所有参数解析器和返回值解析器

    后续用这个对象去反射method对象

    image

     2.3. 参数解析

    在执行方法之前,肯定是需要获取对request的参数解析,并映射到方法的参数列表中。

    image

    image

    这里会进行方法参数类型的获取

    入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息

    image

    2.3.1 参数解析器的查找

    解析之前会从参数解析器列表里进行匹配,如果找不到对应的解析器会报错

    image

    同样的是策略设计模式,每个参数解析器都会提供是否支持解析该参数类型的方法supportsParameter(parameter)

    image

    循环所有解析器,这里有26个解析器 

    image

    分别调用他们的supportsParameter(parameter)方法

    image

    如果有一个支持解析该参数的参数解析器,就返回true.

    这里几个常用的解析器

    RequestParamMethodArgumentResolver  解析@RequestParam注解的参数
    
    PathVariableMethodArgumentResolver 解析@PathVariable 注解的参数
    
    ServletModelAttributeMethodProcessor 解析@ModelAttribute注解的参数
    
    RequestResponseBodyMethodProcessor 解析@RequestBody注解参数,同时返回@ResponseBody返回值也由它解析
    

    2.3.1 循环解析参数

    循环每个参数类型,创建对应长度的数组args[],解析完一个就放到args[对应下标]中

    image

    我们准备好controller_method

    image

    用postman调用一下

    image

    分别看下这些类型的参数对应的解析器是如何解析参数的

    ServletModelAttributeMethodProcessor @ModelAttribute
    RequestParamMethodArgumentResolver @RequestParam
    PathVariableMethodArgumentResolver @PathVariable 
    RequestResponseBodyMethodProcessor @RequestBody
    
  1. 第一个参数 :@ModelAttribute("ma") String ma

前面讲到@ModelAttribute方法被调用之后放到了ModelAndViewContainer中

第一个参数对应获取到的解析器是ServletModelAttributeMethodProcessor

image

ServletModelAttributeMethodProcessor的resolveArgument方法继承父类ModelAttributeMethodProcessor,进入父类的该方法

先获取到方法中定义的参数名称和参数上的ModelAttribute注解,并建立注解和参数名称的绑定关系

image

首先根据参数名称去mavContainer获取

image

如果获取不到的话,就根据注解里的值去mavContainer获取

最后获取到了返回

image

      2.第二个参数 @RequestParam String name

如果方法中没有加任何参数注解,那么默认是当成@RequestParam来处理的

果然在查找解析器的结果是RequestParamMethodArgumentResolver 类

image

进入该类的resolveArgument方法实现至父类AbstractNamedValueMethodArgumentResolver

点到父类的resolveArgument方法

首先获取参数名称

image

 resolveName方法则是从request.getParameter的形式获取值

image

        3.第三个参数 @PathVariable String name

这种类型的参数获取到的解析器是 PathVariableMethodArgumentResolver

image

 

2.4. Controller方法调用,重点看看

回到RequestMappingHandlerAdapter.invokeHandlerMethod()

image

image

获取到参数之后,反射调用

image

image

2.5. Controller方法调用完之后,需要对返回值进行处理

会先把返回值封装成一个ReturnValueMethodParameter对象

image

2.5.1 获取返回值处理类

image

这里同样用策略模式,

  1. 返回值是@ResponseBody,会获取到RequestResponseBodyMethodProcessor解析类

    image

    RequestResponseBodyMethodProcessor是判断方法返回值有没有@ResponseBody注解,我们的返回值类型的确是@ResponseBody

    image

    2.5.2 处理返回值 

    image

    进入这个类的handleReturnValue 看到他封装了下request,response对象 

    image

    后面他会用消息转换器来处理

    这里有8个消息转换器,当前方法匹配到的StringHttpMessageConvert方法

    image

    最后会用类似于response.write,以流的形式返回出去

    image

    image

    如果返回值是一个@Response 的java对象,则默认会匹配到MappingJackson2HttpMessageConverter 消息转换器

    他会先把要返回的信息先序列化一下,再输出

    image

  2. 返回值是单纯的视图的话,就会匹配这个返回值处理器ViewNameMethodReturnValueHandler他的处理方法会把方法的返回值作为视图名称设置到 mavContainer.view当中,由后面的视图渲染来处理

    image

    2.6. 返回ModelAndView

    处理请求方法最后面会把根据mavContainer创建一个ModelAndView对象,里面装了modelMap以及视图

    image

    至此,controller方法处理完毕 

原文:springmvc源码分析:处理请求核心流程之controller_method的调用

おすすめ

転載: blog.csdn.net/meser88/article/details/120863006