spring-mvc请求处理过程源码分析笔记

前言

HandlerAdapter 是一种 SPI 实现方式,这种 SPI 实现方式在 spring 中有很多处应用。

正文

在某一 Controller 方法上加断点,走到断点处,在调试视图中通过调用栈视图可看到 spring-mvc 的入口点为 FrameworkServlet 的 doService,我们可在此加断点,从新来一遍进行分析

整体概念

DispatcherServlet 做请求分发

分发是根据 HandlerMapping 获得 Handler 然后封装成 HandlerExecutionChain

HandlerExecutionChain中包含两部分,一部分是标识执行主体的HandlerMethod,另一部分是其拦截器集合,拦截器分别在其执行handle前、后执行。

HandlerMethod 会再封装为 HandlerAdapter 在其中用反射调用真正的 Controller中的方法逻辑

大流程

  • 入口 FrameworkServlet 模板方法 doService

  • DispatcherServlet 实现 doService

org.springframework.web.servlet.DispatcherServlet#doService

  • doDispatch 做请求分发

org.springframework.web.servlet.DispatcherServlet#doDispatch

  • getHandler 获得 HandlerExecutionChain,HandlerExecutionChain是Handler(也就是Controller)和一组HandlerInterceptor的聚合 org.springframework.web.servlet.DispatcherServlet#getHandler 其内部处理流程:
    • 循环 this.handlerMappings 调用每一个 mapping 的 getHandler :org.springframework.web.servlet.HandlerMapping#getHandler 其内部处理流程:
      • org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerInternal 获得HandlerMethod(实际上也就是我们写的Controller中各种标记了@RequestMapping的方法包装后的结果)
      • 如果上一步获得的是null那么就获得默认的handler org.springframework.web.servlet.handler.AbstractHandlerMapping#getDefaultHandler
      • 如果上一步默认handler也为null那么直接返回null退出方法
      • 如果 handler instanceof String 那么证明handler是需要通过Bean名字从ApplicationContext里拿,如果是那么就去拿出来
      • org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain 获得 HandlerExecutionChain 并返回,其内部处理流程:
        • 如果handler不是HandlerExecutionChain类型的,那么将handler套入new HandlerExecutionChain() 创建成 HandlerExecutionChain
        • 获得Handler的lookupPath,也就是我们自己写的Controller的RequestMapping中的URI
        • 循环所有MappedInterceptor看起是否match到lookupPath,如果match到则此拦截器放到第一步生成的HandlerExecutionChain中然后返回
    • 遇到第一个不为null的HandlerExecutionChain 立刻(跳出循环)返回
  • 将上一步产生的HandlerExecutionChain中的HandlerMethod拿出来当作参数传入getHandlerAdapter获得HandlerAdapter ,HandlerAdapter 是一个SPI,用于外部扩展干预spring-mvc内部流程用的,其内部流程:

    • 循环handlerAdapters找到第一个supports的就返回
  • Process last-modified header 处理 last-modified

  • org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle 进行handle前处理

  • org.springframework.web.servlet.HandlerAdapter#handle 进行真正的Handler的handle(也就是 Controller 中对应的我们自己实现的逻辑)并返回 ModelAndView 其内部处理流程:

    • 调用 checkRequest 校验是否支持当前请求方法类别
    • 将HandlerMethod 封装为 InvocableHandlerMethod 并执行其 invokeAndHandle,在其内部流程中最终会通过反射( java.lang.reflect.Method#invoke)执行HandlerMethod中对应的我们自己定义的Controller中的方法
    • 调用 getModelAndView 完成并返回
  • org.springframework.web.servlet.DispatcherServlet#applyDefaultViewName 为上一步返回的 ModelAndView 应用DefaultViewName 其内部流程:

  • org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle 进行handle后处理

  • org.springframework.web.servlet.DispatcherServlet#processDispatchResult 完成处理