1.Spring MVC源码分析(二)
在之前的一篇文章中Spring MVC源码分析(一),已经讲了Spring MVC初始化和执行的大概流程,对于执行的doDispatch
方法,我们并没有详细的去说,那么这篇文章就是针对具体的执行去分析。
首先,看下org.springframework.web.servlet.DispatcherServlet#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);
// Determine handler for the current request.
//1.获取Handler,其实HandlerExecutionChain,这个类包含了Handler和HandlerInterceptor
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//2.找到Handler的适配器,因为Handler是Object,所以通过SPI机制,找到对应Handler的适配器
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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//3.org.springframework.web.servlet.HandlerInterceptor#preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//4.真正的去执行
//对于@RequestBody、@ResponseBody、@RestController等注解使用的是AbstractHandlerMethodAdapter
//这个方法里面主要三步:
//1.参数解析:涉及转换器
//2.反射执行
//3.结果封装:涉及转换器
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//5.将请求转为视图名称
applyDefaultViewName(processedRequest, mv);
//6.org.springframework.web.servlet.HandlerInterceptor#postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//7.视图渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//8.org.springframework.web.servlet.HandlerInterceptor#afterCompletion
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);
}
}
}
}
上面的注释,就是doDispatch
的执行流程,我们就按照这个注释流程一步一步去看。
1.HandlerMapping和Handler
第一步是根据HandlerMapping
获取``Handler,但实际上这里返回的
HanlderExecutionChain,
HandlerExecutionChain里面封装了
Hanlder和
HandlerInterceptor,所以说本质上和
Handler`是差不多的。
HandlerMapping
是一个请求映射器,作用是根据请求来获取能够处理该请求的处理器。
org.springframework.web.servlet.DispatcherServlet#getHandler
:
/**
* HandlerExecutionChain 是对Handler和HandlerInterceptor的一个封装
* 注意:
* 1)、Handler是一个Object类型,是为了其他的第三方框架能够实现自己的Handler
* 2)、HandlerInterceptor其实就是拦截器
* @param request
* @return
* @throws Exception
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//1.HandlerMapping初始化过程已经说过了
//通过遍历容器中所有的HandlerMapping,获取能够处理该请求的Handler
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
:
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//1.这是获取Handler的核心方法,是一个钩子方法,完全交由子类实现,我们重点是要看这里
Object handler = getHandlerInternal(request);
if (handler == null) {
//2.如果没有找到,获取默认的Handler
handler = getDefaultHandler();
}
if (handler == null) {
//3.如果都没有找到,doDispatch会判空,抛出404 NotFoundException
return null;
}
// Bean name or resolved handler?
//4.判断Handler是不是一个Bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//5.封装HandlerExecutionChain,这里会封装HandlerInterceptor
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
//跨域
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
下图展示了两个主要实现类:

这里有两个抽象实现,org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
是处理所有被@Controller
或@RequestMapping
注解的类;org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
根据给定的url进行处理。
这里我们看org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
:
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//1.获取请求路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
//2.根据url 获取Handler
//HandlerMethod封装了:controller bean、controller bean type、invoke method、invoke method arguments,这也就意味着可以通过反射去执行
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
:
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//1.返回符合的RequestMappingInfo,RequestMappingInfo就是IOC容器启动的时候初始化的扫描所有被@Controller或@RequestMapping注解的类的相关信息
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//2.设置匹配器
addMatchingMappings(directPathMatches, matches, request);
}
//3.如果没有找到符合的RequestMappingInfo,则设置所有的RequestMappingInfo
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
//4.这一步目地是如果只有一个符合的Handler,直接返回即可,如果有多个符合的Handler,则进行比较,返回一个最合适的
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
//5.返回最佳匹配
return bestMatch.handlerMethod;
}
else {
//6.匹配器不存在返回NULL
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
那么经过这几个步骤之后,我们就已经拿到了HandlerMethod
也就是Handler
,再经过封装HandlerInterceptor
,我们的doDispatch
就拿到了一个HandlerExecutionChain
类,第一步也就完成了这里我把HandlerExecutionChain
这个类贴出来,以便更好的理解这个类。

2.HandlerApapter
根据HandlerExecutionChain
类,我们已经知道了Handler
是一个Object
,目的是为了给其他第三方框架进行扩展。既然Handler
是一个Object
,那么我么肯定就不可能拿到Handler
就直接反射执行,因为直接执行我们会增加很多判断,这对于DispatcherServlet
来说是很不友好的,所以Spring MVC
就定义了你如果扩展了Handler
,那么你也要给一个你的Handler
的HandlerAdapter
,HandlerAdapter
是以SPI
机制进行加载的。
org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//1.遍历已经初始化的HandlerAdapter
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
//2.判断是否支持这个Handler
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
:
/**
* 专门用来处理HandlerMethod的
* @param handler
* @return
*/
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal
:
/**
* 总是返回true
* @param handlerMethod the handler method to check
* @return
*/
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
我们第一步拿到的Handler
是HandlerMethod
,那么在获取HanlderAdapter
的时候就比较简单了,拿到的是org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
,第二步也就完成了。
3.HandlerAdapter#handle
上一步我们已经拿到了HandlerAdapter
,那么下面我们就可以去执行了,因为HandlerInterceptor
的存在,在真正的handle
之前,需要先执行org.springframework.web.servlet.HandlerInterceptor#preHandle
,这里比较简单,我们直接看真正的执行。
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
:
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
* 模板方法
*/
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//1.钩子方法,完全交由子类实现
return handleInternal(request, response, (HandlerMethod) handler);
}
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
:
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
//1.检查请求
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
//2.是否需要加锁
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
//3.执行,一般会走这里
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
:
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1.处理请求
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
//2.非@ResponseBody直接返回
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//3.处理@ResponseBody,涉及转换器
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
:
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1.解析参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
//2.反射执行
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
这个方法有两个重要的步骤:1.解析参数;2.反射执行。
1.解析参数
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1.获取方法参数
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
//2.判断参数类型是否符合
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
//3.解析参数
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
//4.返回参数列表
return args;
}
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument
:
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//1.获取参数解析器
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
//2.@RequestBody 解析参数使用org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
//我们主要看这里
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument
:
/**
* @RequestBody注解参数解析
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
//1.转换器,我们只要知道这里面是根据Content-Type通过我们配置的转换器来设置参数即可
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
//2.数据绑定
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
//3.是否需要适配参数
return adaptArgumentIfNecessary(arg, parameter);
}
2.反射执行
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
//1.反射执行
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
String text = getInvocationErrorMessage("Failed to invoke handler method", args);
throw new IllegalStateException(text, targetException);
}
}
}
到这里我们的Handler
也就执行完了,下面就是对返回值进行处理了。这里我们直接看对@ResponseBody
的处理。
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue
:
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//2.org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue
:
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
//1.转换器处理
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
从请求参数处理到返回参数处理,我们都可以看到一个重要的类org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
,这个类就是对@RequestBody
和@ResponseBody
通过转换器进行处理。
到这一步,我们整个Handler
就已经执行完成了,这个时候会调用org.springframework.web.servlet.HandlerInterceptor#postHandle
进行处理。
4.HandlerExceptionResolver
异常处理器,用于对Handler
执行抛出的异常。
org.springframework.web.servlet.DispatcherServlet#processDispatchResult
:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
//1.处理异常
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 2.HandlerExceptionResolver
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//3.视图渲染
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
//4.触发HandlerInterceptor#afterComplete
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
这个方法包含了:1.异常处理;2.视图渲染;3.正常请求的HandlerInterceptor#afterComplete
。
org.springframework.web.servlet.DispatcherServlet#processHandlerException
:
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
//1.遍历所有的HandlerExceptionResolver,包括我们自定义的,进行异常处理
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
//2.是否有View
if (!exMv.hasView()) {
exMv.setViewName(getDefaultViewName(request));
}
if (logger.isDebugEnabled()) {
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
至此,异常处理也就完成了,最后下面就是视图渲染了,因为无论是否有异常,有可能包含视图渲染,所以我们可以看到视图渲染render
和异常处理processHandlerException
是在同一个方法中。
5.ViewResolver
视图解析器,用来查找我们要显示到前端的页面。
org.springframework.web.servlet.DispatcherServlet#render
:
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.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
//1.根据名称获取视图
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), 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.
//2.保存的就是视图本身
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.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//3.视图渲染
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
org.springframework.web.servlet.view.AbstractView#render
:
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
//1.创建需要合并的Model,包括static attributes和RequestContext attribute
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
//2.渲染合并的Model
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
:
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
//1.暴露Model作为Attributes
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
//2.如果需要,支持JSTL
exposeHelpers(request);
// Determine the path for the request dispatcher.
//3.确定路径
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
//4.请求分发
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
//5.如果已经执行了,则进行转发,否则执行
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(request, response);
}
else {
//6.转发
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.forward(request, response);
}
}
正常的流程走完了,上述任何一个步骤发生了异常,都会直接执行HandlerInterceptor#afterComplete
方法。