SpringMVC工作流程

SpringMVC工作流程

SpringMVC几大核心组件

  • DispatcherServlet:所有请求的入口,所有请求都会被打到这个servlet上,由它来做统筹
  • RequestHandlerMapping:由它来做请求的匹配,返回一个处理本次请求的HandlerExecutionChain
  • RequestHandlerAdapter:由它来做handler的适配,执行业务逻辑
  • ViewResolver:由它做视图解析
  • HandlerExceptionResolver:当出现异常的时候由它来做处理

下面从统筹者逐步分析工作流程

DispatcherServlet的继承体系

通过继承体系可以得知以下几点

1、DispatcherServlet本质上是一个servlet

2、内部注入了

  • Environment:项目的运行环境
  • ApplicationContext:Spring容器

Servlet的生命周期

回顾一下Servlet的生命周期

  • init:在servlet被初始化的时候执行
  • service:在接收请求的时候执行该方法
  • destory:被销毁的时候执行该方法

刚刚说了DispatcherServlet本质上就是Servlet,那就一定也有这三个生命周期

Servlet接口

可以看到这三个方法就对应着三个生命周期

初始化init

这里我们采用从上往下找,也就是从父类往子类找

GenericServlet

HttpServlet

此类中没有定义初始化的逻辑

HttpServletBean

FrameworkServlet

initWebApplicationContext

DispatcherServlet

onRefresh方法

终于到九大护法出场的时候了

initMultipartResolver

可以看到尝试了从容器中拿,找不到就直接赋值为null了

也就是说,如果我们自己不提供multipartResolver的Bean,我就不装载它

SpringBoot中是默认加载multipartResolver

自动配置类如下

initLocaleResolver

可以看到和刚刚的initMultipartResolver差不多

区别就是就是如果在容器找不到LocaleResolverDispatcherServlet就会找默认的LocaleResolver

getDefaultStrategy

此方法就是返回指定类的默认实现

getDefaultStrategies

DispatcherServlet的同级目录下找到DispatcherServlet.properties文件

initThemeResolver

和刚刚的initLocaleResolver一样

如果在容器中找不到,就直接找默认策略

initHandlerMappings
initHandlerAdapters
initHandlerExceptionResolvers
initRequestToViewNameTranslator
initViewResolvers
initFlashMapManager

小总结

好了,初始化流程就这些,是不是很简单😄😄😄

主要初始化了以下这些组件

1、MultipartResolver:处理文件上传的

2、LocaleResolver:国际化相关组件

3、ThemeResolver

4、HandlerMappings:匹配请求路径,创建对应的HandlerExecutionChain

5、HandlerAdapters:根据刚刚创建的HandlerExecutionChain中的Handler匹配对应的HandlerAdapter

6、HandlerExceptionResolvers:异常解析器

7、RequestToViewNameTranslator:将请求路径转化为视图名

8、ViewResolvers:视图解析器,解析ModelAndView

9、FlashMapManager

接下来的service才是重头戏

接收请求service

GenericServlet

这个方法是抽象的,交给子类去实现

HttpServlet

service
doGet
doHead
doPost
doPut
doDelete
doOptions
getDeclaredMethods

c.getDeclaredMethods()调用的是Class类的方法,返回的是这个类定义的所有方法,包括私有方法

接着看doOptions方法

FrameworkServlet

PATCH请求方式是什么?

传送门:https://www.jianshu.com/p/bee85cf4e33a

好,也就是说如果请求方式是PATCH,那么就走processRequest方法

如果不是PATCH方式,就走父类的service方法

等等,父类的service方法,那不是HttpServletservice方法吗

这个service方法中根据请求方式的不同,将请求分发到不同的doXxx方法

doGet、doPost、doPut、doDelete方法
doOptions
doTrace
doHead

FrameworkServlet中并没有doHead方法,说明是直接复用的父类HttpServletdoHead方法

processRequest(❗关键)

可以看到很多doXxx中都调用了processRequest方法,下面让我们来揭开它的面纱

好接下来的关键就是doService方法了

抽象方法,那就要找子类了,FrameworkServlet的子类,那就是我们的主角DispatcherServlet

DispatcherServlet

doDispatch(❗❗❗关键中的关键)

走到这里,其实才是我们的mvc框架大展神威的时候,开头提到的三大护法将一 一现身

HandlerExecutionChain
1、checkMultipart
2、getHandler
3、getHandlerAdapter
4、applyPreHandle

没有一个拦截器返回false的情况

中间有一个拦截器返回false的情况

5、handle

好,这个ha是一个HandlerAdapter接口实现类

我们跑个程序让断点停在这

控制器定义如下

点进去

invokeHandlerMethod

invokeAndHandle

getMethodArgumentValues

具体解析参数的逻辑就不在这里看了,后续文章可以写一下

doInvoke

回到刚刚调用invokeForRequest的地方

writeWithMessageConviters方法就是将方法返回值转化为json后将其写到response中,具体执行逻辑后续文章可以写一下

好,这个方法执行完之后,回到刚刚RequestMappingHandlerAdapterinvokeHandlerMethod的地方,然后就是获得ModelAndView对象了

getModelAndView

这里是true的原因

然后一直往回走,一直回到RequestMappingHandlerAdaptorhandleInternal方法得到这个ModelAndView对象

ModelAndView对象返回到DispatcherServletha.handle方法

小总结

这个handle方法干的事情还真多啊,对它的功能做一下小总结

1、执行目标方法(就是对应Controller中的方法)

2、将响应信息写入response中

3、构建ModelAndView对象(如果需要的话)

6、applyPostHandle

这里就是执行拦截器链的postHandle方法

可以看到这里是直接从拦截器尾部开始往前遍历的

7、processDispatchResult

processHandlerException


回到刚刚的processDispatchResult下半部分

小总结

DispatcherServlet此块功能做个小总结

1、根据请求方法将请求分发到对应的doXxx方法(从HttpServlet继承来的方法)

2、FrameworkServlet方法复写这些doXxx方法,都使用到了一个方法processRequest

3、在processRequest方法中,放出了一个doService抽象方法被DispatcherServlet实现

4、在doService方法中,又调用了本类的doDispatch方法

5、getHandler(processedRequest)使用成员属性handlerMappings匹配并创建HandlerExecutionChain

6、getHandlerAdapter(mappedHandler.getHandler())使用成员属性handlerAdapters匹配可以处理HandlerExecutionChain中的handlerHandlerAdapter

7、mappedHandler.applyPreHandle(processedRequest, response)执行拦截器链的preHandle方法

8、 ha.handle(processedRequest, response, mappedHandler.getHandler())执行目标方法中的逻辑,并创建ModelAndView(如果有的话)

9、mappedHandler.applyPostHandle(processedRequest, response, mv)执行拦截器链的postHandle方法

10、processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)执行过程中如果有异常需要用成员属性handlerExceptionResolvers处理异常指定错误视图,并且执行拦截器链的afterCompletion方法

销毁destroy

GenericServlet

HttpServlet

该类中没有复写destroy方法

HttpServletBean

该类中没有复写destroy方法

FrameworkServlet

DispatcherServlet

该类中没有复写destroy方法

小总结

也就是说只有FrameworkServlet中定义了destroy方法,也就是关闭web容器

时序图

给作者买杯咖啡吧~~~