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
差不多
区别就是就是如果在容器找不到LocaleResolver
,DispatcherServlet
就会找默认的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
请求方式是什么?
好,也就是说如果请求方式是PATCH
,那么就走processRequest
方法
如果不是PATCH
方式,就走父类的service
方法
等等,父类的service
方法,那不是HttpServlet
的service
方法吗
这个service
方法中根据请求方式的不同,将请求分发到不同的doXxx
方法
doGet、doPost、doPut、doDelete
方法
doOptions
doTrace
doHead
在FrameworkServlet
中并没有doHead
方法,说明是直接复用的父类HttpServlet
的doHead
方法
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中,具体执行逻辑后续文章可以写一下
好,这个方法执行完之后,回到刚刚RequestMappingHandlerAdapter
的invokeHandlerMethod
的地方,然后就是获得ModelAndView
对象了
getModelAndView
这里是true的原因
然后一直往回走,一直回到RequestMappingHandlerAdaptor
的handleInternal
方法得到这个ModelAndView
对象
将ModelAndView
对象返回到DispatcherServlet
的ha.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
中的handler
的HandlerAdapter
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容器