SpringMVC请求执行过程拆分成主要的7步。
请求发起后会进入DispatchServlet中doDispatch。下一篇文章讲解如何进入DispatchServlet中doDispatch,和启动SpringMVC容器时做的前期准备(初始化handlerMappings,handlerAdapters…)。
整体流程:
组件:
1、前端控制器DispatcherServlet(不需要程序员开发)
作用接收请求,响应结果,相当于转发器,中央处理器。
有了DispatcherServlet减少了其它组件之间的耦合度。
2、处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的url查找Handler
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
4、处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、视图解析器View resolver(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6、视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(InternalResourceView、freemarkerView)
一、getHandler
getHandler中遍历handlerMappings获取handler,handlerMappings中包含下图类型的handlerMapping。
以RequestMappingHandlerMapping为例。其中HandlerMethod包含了请求对应的handler的请求处理方法如图
查看RequestMappingHandlerMapping
父类RequestMappingInfoHandlerMapping
父类RequestMappingInfoHandlerMapping
父类AbstractHandlerMethodMapping
父类AbstractHandlerMapping
AbstractHandlerMapping 中getHandler->getHandlerInternal(AbstractHandlerMethodMapping)->lookupHandlerMethod(AbstractHandlerMethodMapping)
通过url匹配相应的HandlerMethod
返回handlerMethod类型的对象如下图。
把获取到的handlerMethod类型的对象传入getHandlerExecutionChain 返回mappedHandler
类型为HandlerExecutionChain其中包含HandlerMethod和所有拦截此请求的拦截器。
二、getHandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
遍历三种类型的HandlerAdaper
以RequestMappingHandlerAdapter类型的HandlerAdapter为例
RequestMappingHandlerAdapter
父类AbstractHandlerMethodAdapter
父类中supports方法判断传入的handler是否为HandlerMethod类型如果能匹配则返回RequestMappingHandlerAdapter类型的HandlerAdapter。在第一步中handler的类型为HandlerMethod类型。所以匹配上RequestMappingHandlerAdapter。
三、applyPreHandle
执行第一步获取的mappedHandler,遍历执行mappedHandler中getHandler阶段保存的拦截此请求的拦截器的preHandle方法。
一旦preHandle返回false拦截器链会终止执行,并执行相应拦截器的triggerAfterCompletion
方法,返回false后,
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
会return不会往下继续执行,请求终止,不会执行第四步及以下步骤。
四、ha.handle
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
继续以第二步获取的RequestMappingHandlerAdapter类型的HandlerAdapter为例
执行RequestMappingHandlerAdapter父类AbstractHandlerMethodAdapter的handle方法,继续调用RequestMappingHandlerAdapte的handleInternal
——>invokeHandleMethod(request, response, handlerMethod)
->createRequestMappingMethod 返回requestMappingMethod
为ServletInvocableHandlerMethod类型的对象。
ServletInvocableHandlerMethod
父类InvocableHandlerMethod
父类HandlerMethod
->requestMappingMethod的 invokeAndHandle方法
(ServletInvocableHandlerMethod)。
->invokeForRequest(InvocableHandlerMethod)
执行handler返回执行结果,此步骤就是调用controller中@RequestMapping对应方法。
getModelAndView返回ModleAndView对象。
五、applyDefaultViewName
一旦ModleAndView中有View后applyDefaultViewName不会在给ModleAndView设置默认的view了。
六、applyPostHandle
遍历执行拦截器链中拦截器postHandle方法。
七、processDispatchResult
执行render(mv, request, response)。
创建view对象 把ModelAndView对象赋值给view.
执行resolveViewName,遍历所有viewResolvers,因为项目中使用的freeMarker模板解析器,所以viewResolvers只有freeMarkerViewResolver.
查看
FreeMarkerViewResolver继承关系,执行resolveViewName
父类AbstractTemplateViewResolver
父类UrlBasedViewResolver
父类AbstractCachingViewResolver
其实执行的父类AbstractCachingViewResolver的resolveViewName
->createView
loadView->buildView(UrlBasedViewResolver)
->AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
getViewClass获取的是FreeMarkerView。最终返回FreeMarkerView。
在配置FreeMarkerViewResolver的时候配置的viewClass
执行resolveViewName返回FreeMarkerView后,执行view.render(mv.getModelInternal(), request, response)
FreeMarkerView继承关系
org.springframework.http.web.servlet.view.freemarker.FreeMarkerView
继承了org.springframework.web.servlet.view.freemarker.FreeMarkerView
->AbstractTemplateView
->AbstractUrlBasedView
->AbstractView
其实执行的是AbstractView中的render
->renderMergedOutputModel(org.springframework.web.servlet.view.freemarker.FreeMarkerView重写了renderMergedOutputModel)
->doRender(org.springframework.web.servlet.view.freemarker.FreeMarkerView)
->template.process(model, response.getWriter())替换页面中表达式为具体返回值并返回页面内容到前台。
还有一个重要的方法exposeHelpers。
子类org.springframework.http.web.servlet.view.freemarker.FreeMarkerView重写了org.springframework.web.servlet.view.freemarker.FreeMarkerView中的exposeHelpers。这里可以统一的往前台赋值。paramMap中放入context_path后,所有FreeMarkerView解析过的视图都可以获取。
执行完render后,最后mappedHandler.triggerAfterCompletion(request, response, null);
遍历执行拦截器链中afterCompletion方法。
补充:
在DispatchServlet中doDispatch最新执行的
processedRequest = checkMultipart(request);判断当前请求是否满足文件类型的请求。一旦满足将会把请求转为MultipartHttpServletRequest类型的请求。
multipartResolver配置,添加CommonsMultipartResolver。执行CommonsMultipartResolver中isMultipart.
请求类型为POST请求并且contentType以multipart开头。满足条件转化为MultipartHttpServletRequest类型请求。