DispatcherServlet调度
前文分析了DispatcherServlet的初始化,本文重点看DispatcherServlet处理请求的细节。
一、处理流程图
1.首先是DispatcherServlet完成initStrategies初始化相关策略 2.收到响应之后,遍历内部的HandMapping策略集合,找到对应的HandleMapping,HandMapping会遍历所有的控制器方法,保存映射关系,这部分可参考:HandlerMapping 3.通过HandMapping拿到HandlerExecutionChain之后,将其封装成HandlerAdapter,Adapter内部封装了HandlerMethod用于执行目标方法 4.Adapter开始执行,依次执行拦截器前置方法,然后执行目标方法得到ModeAndView,再将ModeAndView通过视图解析器处理得到结果示图,然后执行后置方法,这里需要注意的是HandlerMethod封装了目标方法所属的Bean对象,通过反射调用目标方法(Method.invoke(Object,arg)); 5.与此同时Adapter还会处理很多参数相关的细节,实现参数绑定,异常处理等; 6.最后渲染View得到包含数据的View,再回调成功后回调方法afterCompletion,返回结果
注意DispatcherServlet本身的处理方法比如doDispatch没有返回值,但是处理完之后会进入父类的逻辑,比如FrameworkServlet,后续会返回响应。
二、处理方法
下图是访问一个Controller方法时的调用栈,从图中可以看出,对于DispatcherServlet而言入口在doService方法。
2.1 doService
doService方法是DispatcherServlet类被调用的入口方法,省略部分日志代码,注释如下:
@Override
protected void doService ( HttpServletRequest request, HttpServletResponse response) throws Exception {
Map< String, Object> attributesSnapshot = null;
if ( WebUtils. isIncludeRequest ( request) ) {
attributesSnapshot = new HashMap < > ( ) ;
Enumeration< ? > attrNames = request. getAttributeNames ( ) ;
while ( attrNames. hasMoreElements ( ) ) {
String attrName = ( String) attrNames. nextElement ( ) ;
if ( this . cleanupAfterInclude || attrName. startsWith ( DEFAULT_STRATEGIES_PREFIX) ) {
attributesSnapshot. put ( attrName, request. getAttribute ( attrName) ) ;
}
}
}
request. setAttribute ( WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext ( ) ) ;
request. setAttribute ( LOCALE_RESOLVER_ATTRIBUTE, this . localeResolver) ;
request. setAttribute ( THEME_RESOLVER_ATTRIBUTE, this . themeResolver) ;
request. setAttribute ( THEME_SOURCE_ATTRIBUTE, getThemeSource ( ) ) ;
if ( this . flashMapManager != null) {
FlashMap inputFlashMap = this . flashMapManager. retrieveAndUpdate ( request, response) ;
if ( inputFlashMap != null) {
request. setAttribute ( INPUT_FLASH_MAP_ATTRIBUTE, Collections. unmodifiableMap ( inputFlashMap) ) ;
}
request. setAttribute ( OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap ( ) ) ;
request. setAttribute ( FLASH_MAP_MANAGER_ATTRIBUTE, this . flashMapManager) ;
}
try {
doDispatch ( request, response) ;
}
finally {
if ( ! WebAsyncUtils. getAsyncManager ( request) . isConcurrentHandlingStarted ( ) ) {
if ( attributesSnapshot != null) {
restoreAttributesAfterInclude ( request, attributesSnapshot) ;
}
}
}
}
2.2 doDispatch
doDispatch是doService方法处理逻辑的主体; doDispatch方法基本上涵盖了一个请求处理的整个流程,包括:获取处理器映射器、包装成适配器、执行拦截器前置方法、目标方法、拦截器后置方法、结果和异常处理。
protected void doDispatch ( HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false ;
WebAsyncManager asyncManager = WebAsyncUtils. getAsyncManager ( request) ;
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart ( request) ;
multipartRequestParsed = ( processedRequest != request) ;
mappedHandler = getHandler ( processedRequest) ;
if ( mappedHandler == null) {
noHandlerFound ( processedRequest, response) ;
return ;
}
HandlerAdapter ha = getHandlerAdapter ( mappedHandler. getHandler ( ) ) ;
String method = request. getMethod ( ) ;
boolean isGet = "GET" . equals ( method) ;
if ( isGet || "HEAD" . equals ( method) ) {
long lastModified = ha. getLastModified ( request, mappedHandler. getHandler ( ) ) ;
if ( new ServletWebRequest ( request, response) . checkNotModified ( lastModified) && isGet) {
return ;
}
}
if ( ! mappedHandler. applyPreHandle ( processedRequest, response) ) {
return ;
}
mv = ha. handle ( processedRequest, response, mappedHandler. getHandler ( ) ) ;
if ( asyncManager. isConcurrentHandlingStarted ( ) ) {
return ;
}
applyDefaultViewName ( processedRequest, mv) ;
mappedHandler. applyPostHandle ( processedRequest, response, mv) ;
}
catch ( Exception ex) {
dispatchException = ex;
}
catch ( Throwable err) {
dispatchException = new NestedServletException ( "Handler dispatch failed" , err) ;
}
processDispatchResult ( processedRequest, response, mappedHandler, mv, dispatchException) ;
}
catch ( Exception ex) {
triggerAfterCompletion ( processedRequest, response, mappedHandler, ex) ;
}
catch ( Throwable err) {
triggerAfterCompletion ( processedRequest, response, mappedHandler,
new NestedServletException ( "Handler processing failed" , err) ) ;
}
finally {
if ( asyncManager. isConcurrentHandlingStarted ( ) ) {
if ( mappedHandler != null) {
mappedHandler. applyAfterConcurrentHandlingStarted ( processedRequest, response) ;
}
}
else {
if ( multipartRequestParsed) {
cleanupMultipart ( processedRequest) ;
}
}
}
}
2.3 getHandler
getHandler获取处理请求的handler,它通过遍历策略属性handlerMappings,一旦找到匹配的HandlerExecutionChain就返回,没有找到则返回null。
@Nullable
protected HandlerExecutionChain getHandler ( HttpServletRequest request) throws Exception {
if ( this . handlerMappings != null) {
for ( HandlerMapping hm : this . handlerMappings) {
HandlerExecutionChain handler = hm. getHandler ( request) ;
if ( handler != null) {
return handler;
}
}
}
return null;
}
2.4 handle
第七步的handle方法是 AbstractHandlerMethodAdapter#handle,方法很简单主要是委托给子类RequestMappingHandlerAdapter#invokeHandlerMethod执行
public final ModelAndView handle ( HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal ( request, response, ( HandlerMethod) handler) ;
}
AbstractHandlerMethodAdapter的handler方法会委托给子类 RequestMappingHandlerAdapter#invokeHandlerMethod执行,RequestMappingHandlerAdapter内部通过HandlerMethod来反射调用;
@Nullable
protected ModelAndView invokeHandlerMethod ( HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod ( handlerMethod) ;
invocableMethod. invokeAndHandle ( webRequest, mavContainer) ;
return getModelAndView ( mavContainer, modelFactory, webRequest) ;
}
走到ServletInvocableHandlerMethod的invokeAndHandle方法,它是HandlerMethod的子类,可以理解为一个包装了目标对象和参数信息的辅助类,这里可以看到反射的影子
public void invokeAndHandle ( ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object. . . providedArgs) throws Exception {
Object returnValue = invokeForRequest ( webRequest, mavContainer, providedArgs) ;
}
继续 InvocableHandlerMethod#invokeForRequest 又走到父类 InvocableHandlerMethod 的 invokeForRequest 方法,
public Object invokeForRequest ( NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object. . . providedArgs) throws Exception {
Object[ ] args = getMethodArgumentValues ( request, mavContainer, providedArgs) ;
Object returnValue = doInvoke ( args) ;
return returnValue;
}
最后 InvocableHandlerMethod#doInvoke 终于可以看到调用目标方法
protected Object doInvoke ( Object. . . args) throws Exception {
ReflectionUtils. makeAccessible ( getBridgedMethod ( ) ) ;
try {
return getBridgedMethod ( ) . invoke ( getBean ( ) , args) ;
}
catch ( IllegalArgumentException ex) {
}
}
这里getBridgedMethod ( ) 会得到一个Method对象,然后Method. invoke ( Object, args) ;
里面的getBean ( ) 调用的就是父类的HandlerMethod里面封装的Bean,其实就是我们的目标Bean,args就是方法参数
上述调用栈一路进去比较深,后续可以参考:05-HandlerMethod
2.5 processDispatchResult
processDispatchResult处理结果,里面会处理异常、根据异常处理示图、调用拦截器的 afterCompletion方法等
private void processDispatchResult ( HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false ;
if ( exception != null) {
if ( exception instanceof ModelAndViewDefiningException ) {
mv = ( ( ModelAndViewDefiningException) exception) . getModelAndView ( ) ;
}
else {
Object handler = ( mappedHandler != null ? mappedHandler. getHandler ( ) : null) ;
mv = processHandlerException ( request, response, handler, exception) ;
errorView = ( mv != null) ;
}
}
if ( mv != null && ! mv. wasCleared ( ) ) {
render ( mv, request, response) ;
if ( errorView) {
WebUtils. clearErrorRequestAttributes ( request) ;
}
}
if ( WebAsyncUtils. getAsyncManager ( request) . isConcurrentHandlingStarted ( ) ) {
return ;
}
if ( mappedHandler != null) {
mappedHandler. triggerAfterCompletion ( request, response, null) ;
}
}
三、小结
主要梳理了DispatcherServlet调度处理一个请求的流程,总结如下:
1. 通过 HandMapping 策略集合得到执行器链HandlerExecutionChain
2. 将HandlerExecutionChain包装成Adapter
3. 执行preHandle
4. Adapter返回ModeView
5. ModeView处理得到View
6. 后置postHandle调用
7.3 - 6 如果有异常,处理异常
8. 渲染View,填充数据
9. afterCompletion方法调用