SpringMVC执行流程

1,009 阅读3分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

SpringMVC的执行流程其实重点就是DispatcherSerlvet、handlermappings,handlerAdapter,viewResolver之间的交互。

流程梗概如下:

  1. 所有的请求会打到DispatcherSerlvet上。

    • DispatcherSerlvet是一个HTTPServlet,SpingMVC所有的请求都打在这个Servlet上。
  2. DispatcherServlet会遍历所有的handlerMappings找到对应的handler并获取到HandlerExecutionChain

    • handlermappings的作用是依据请求的url找到对应的handler,也就是该url对应的方法。
      • 这里面主要有3个handlermappings:分别对应的controller的三种实现
        • spring mvc 有两大类型,三种方式实现controller层
          • 两大类型
            • BeanName方式:以BeanName来作为url。
            • RequestMapping方式:RequestMapping注解方式标注url。
          • 三种方式
            • 实现controller接口+component注解 (beanName就是path)。

            • 实现HttpRequestHandler接口+component注解(beanName就是path)。

            • Controller注解和RequestMapping注解。(最多的是用这种)

    • HandlerExecutionChain 这个handler执行链对象就是请求路径对应controller的方法封装的对象HandlerMethod,和一个拦截器list。
  3. 上面的HandlerExecutionChain会接着遍历handlerAdapters找到对应的handlerAdapter 并包装为获取HandlerAdapter(后续的操作都是这个Adapter在操作)

    • 为什么需要这些Adapter?
      • 上面也说了,controller是可以有多种方式实现的。那么不同方式去调用对应方法的方式也是不一样的!
        • 问:Java调用另外一个类的方式
          • new对象调用(不可取,SpringMVC不可能动态知道调用哪个方法-没法写死在代码里面)
          • 接口调用(定死一个接口,代码里面直接调接口方法,但是灵活度就差了,只能少量定死的接口方法)
          • 反射调用(灵活度高,效率差)
        • SpringMVC实现
          • BeanName方式的controller实现,用的是接口的方式
          • RequestMapping方式用的是反射
        • 如果不加这些Adapter的话,就需要一堆的if-else去判断了。定义这些Adapter可以适应各种场景!
  4. HandlerAdapter 最终会调用handle方法执行对应controller的方法并返回ModelAndView。

  • 这个handler会从request拿取到参数,然后通过反射到的Method对象,遍历参数列表,并通过一系列的参数解析器(类似于RequestParam/Path等等这些就是通过解析器来解析的)将参数解析到方法对应的实参,最后invoke调用controller的方法。

  • 番外:springMVC是基于反射调用方法的,JDK8之前,反射是无法获取到参数名称的,参数都会被简化为arg0..n,SpringMVC是基于ASM字节码方式去拿的(1.8之后,开启-parameters就可以拿到)。所以说:SpringMVC还可以根据参数名自动匹配,不需要写requstparm这些注解。

    • 解析参数:1. 优先是注解的 2. 然后JDK反射的-只针对1.8+ 3. 无奈只能ASM的。
  • 如果controller方法加了@ReponseBody注解,那么modelAndView会直接返回null,就直接返回到response,不会再走下面的视图解析过程了。

  1. DispatcherSerlvet获取到ModelAndView交给视图解析器ViewResolver,解析器会将其解析成view。

  2. DispatcherServlet根据获取到View进行视图渲染,并将视图返回给用户。