以下源码分析基于
Spring的5.1.3
版本
先上SpringMVC的流程图:
我们知道DispatcherServlet
是SpringMVC的一个关键类,关键点 是DispatcherServlet
重写了FrameworkServlet
的doService()
方法,doService()
又调用了doDispatch()
方法,这两个方法是整个程序的关键点。接下来的分析会穿插SpringMVC各个组件来对DispatherServlet
进行分析。
初始化组件initStrategies()
DispatcherServlet
首先做的就是初始化工作,看initStrategies()
方法:
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);//初始化上传请求组件
initLocaleResolver(context);//国际化解析器
initThemeResolver(context);//主题解析器
initHandlerMappings(context);//处理器映射器
initHandlerAdapters(context);//处理器适配器
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);//视图解析器
initFlashMapManager(context);//重定向属性管理器
}
我们可以看到initStrategies()
方法里面初始化了Multipart组件、国际化解析器、主题解析器、一堆处理器映射器、一堆处理器适配器、视图解析器、重定向属性管理器等等,这样初始化后,诸如处理器映射器、处理器适配器等的组件就可以在后面使用了。
doService()
doService()
源码如下:
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
//1、首先判断是不是 include 请求,如果是则对 request 的 Attribute 做个快照备份
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));
}
}
}
// 提供框架对象处理程序和视图对象。(也就是Spring MVC中特殊的几个bean)
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
// spring mvc支持i18n
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
// spring mvc支持主题
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
// 2、重定向属性处理,对Redirect的支持,解决了POST/Redirect/GET模式问题
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 {
// 3、前端处理请求分发
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// 4、等 doDispatcher 处理完之后(如果不是异步调用且未完成)对已备份好的快照进行还原 ,在做完快照后又对 request设置了一些属性。
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
可以看到doService()
方法里面首先判断请求是否为include请求,如果是则将request的attributes做一个快照备份。等doDispatcher()
处理完后就(如果不是异步调用且未完成)进行还原 ,在做完快照后又对 request 设置了一些属性。
doDispatcher()
doDispatcher()
开始真正对请求进行处理分发。这个方法是整个DispatcherServlet
的重点,中间会穿插一些SpringMVC的组件来讲,篇幅较长。
上源码(里面的注释会有对源码的解释):
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 {
//1、先检查请求是不是Multipart请求,如果是则返回已处理的request,否则返回原来的request
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//2、遍历HandlerMappings集合,根据HandlerMapping来获取HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);//对response进行处理,返回404
return;
}
//3、根据Handler(该Handler是在由request获取回来的HandlerExecutionChain里面的)返回适配的HandlerAdapter
// HandlerAdapter里有handle()方法,这个方法就是实际执行Controller方法的地方
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
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;
}
}
//4、HandlerExecutionChain里注册了一系列拦截器(包括你自己定义并注册了的拦截器以及Spring的拦截器),而applyPreHandle()就是执行一系列拦截器的地方
//如果拦截器不拦截,则继续流程(拦截器会在另一篇博文讲)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//5、这里调用HandlerAdapter里的handle()方法,这个方法就是实际执行Controller里的方法的地方
// 处理完后会返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//6、用RequestToViewNameTranslator组件生成ViewName字符串并设置到ModelAndView里
applyDefaultViewName(processedRequest, mv);
//7、调用HandlerExecutionChain的拦截器的postHandle()方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
//用在下面的processDispatchResult()方法里
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//8、渲染view视图,以及调用HandlerExecutionChain里的拦截器的afterCompletion()方法
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()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
源码分析
以下前序与上面源码注释的前序对应
1、先利用MultipartResolver
的isMultipart()
来判断请求是不是multipart请求,如果是,则用resolveMultipart()
将request包裹成MultipartHttpServletRequest
并将其返回,否则返回原request。
//跳转-->doDispatch()
processedRequest = checkMultipart(request);
//------------------------------------------
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
//...
//
return this.multipartResolver.resolveMultipart(request);
//...
}
return request;
}
2、HandlerMapping
有一个getHandler()
方法,该方法用来获取HandlerExecutionChain
。因为在DispatcherServlet里一开始已经初始化了一堆HandlerMappings,于是遍历所有的已注册HandlerMapping
,并调用它的getHandler()
方法来获取HandlerExecutionChain
。
//跳转-->doDispatch()
mappedHandler = getHandler(processedRequest);
//---------------------------------------------
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
3、获取HandlerExecutionChain
之后,就要获取HandlerAdapter
。先从初始化得来的一堆HandlerAdapters中,调用HandlerAdapter
的support()
方法看看该HandlerAdapter
是否支持该处理器,若支持就返回该HandlerAdapter
//跳转-->doDispatch()
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//---------------------------------------------------------------------
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
//...
}
4、因为HandlerExecutionChain
里面有处理器Handler和拦截器,这里是在调用处理器前,先调用拦截器的preHandle()方法。
//跳转-->doDispatch()
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//--------------------------------------------------------------
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
5、执行完拦截器的preHandle()
后,程序就调用HandlerAdapter
的handle()
方法,该方法是真正执行Controller方法的入口,执行完Controller方法后就返回ModelAndView
。
//跳转-->doDispatch()
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//跳转-->HandlerAdapter
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
关于HandlerAdapter
接口,SpringMVC有具体的实现类,如:
我会另开一篇博文详细讲解SpringMVC的各个组件,里面会讲解HandlerAdapter
的实现类。
6、这里涉及到RequestToViewNameTranslator
这个组件,SpringMVC有一个实现类DefaultRequestToViewNameTranslator
。用RequestToViewNameTranslator
组件的getViewName()
,将HttpServletRequest请求的uri转换成ViewName字符串并设置到ModelAndView里。
//跳转-->doDispatch()
applyDefaultViewName(processedRequest, mv);
//跳转-->applyDefaultViewName()
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
//跳转-->getDefaultViewName()
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
}
//跳转-->DefaultRequestToViewNameTranslator # getViewName()
public String getViewName(HttpServletRequest request) {
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
return (this.prefix + transformPath(lookupPath) + this.suffix);
}
7、遍历拦截器,调用拦截器的postHandle()
方法
//跳转-->doDispatch()
mappedHandler.applyPostHandle(processedRequest, response, mv);
//--------------------------------------------------------------
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
8、这个processDispatchResult()处理Handler执行后的结果,将ModelAndView或者Exception(这里又涉及到HandlerExceptionResolver
这个组件,将Exception处理成ModelAndView)渲染成视图,然后调用render()生成页面
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
//将Exception包裹成ModelAndView
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
//...
render(mv, request, response);
//...
if (mappedHandler != null) {
//执行拦截器的afterCompletion()方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
可以看到render()
就是通过resolveViewName()
来用ModelAndView
里的ModelMap
渲染生成View
,这里涉及到ViewResolver
和LocaleResolver
组件。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
ViewNameTranslator
以及ViewResolver
组件在生成View视图的时候会被调用
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers)
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}