在用户发起请求后经过FrameworkServlet后会进入DispatcherServlet的doService方法。
doService方法。该方法主要是将一些参数设置到请求中让handler和view对象可用。然后请求核心方法doDispatch()
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.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 {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
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 {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
// 判断这个请求是否是Multipart,比如文件上传就是Multipart请求。如果是Multipart请求就交给multipartResolver处理,如果不是Multipart返回当前的请求。
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 获取处理器
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 获取处理器适配器
HandlerAdapter ha = this.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;
}
}
// 执行拦截器中的前置方法,如果返回false就不再执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行真正的处理方法(Controller中的方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果ModelAndView中没有视图引用,那么申请设置默认的视图名称
this.applyDefaultViewName(processedRequest, mv);
// 执行拦截器中的后置方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 处理程序调用返回的结构进行处理 详情见2.7
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
// 资源清理
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
在getHandler(processedRequest)里面通过遍历所有的handlerMapping,调用handlerMapping对象中的getHandler(request)方法获得HandlerExecutionChain对象。其中关键方法为 mapping.getHandler(request);下方详解
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
在进入AbstractHandlerMapping中的getHandler方法后主要方法就是getHandlerInternal,其他就是构造执行链,故直接看getHandlerInternal方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 从请求中获取lookupPath
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
// mappingRegistry是映射关系注册中心,其中维护mapping到处理程序handlerMethod的映射关系
// 取锁
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
// 获取处理器,lookupHandlerMethod方法,见2.5
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
// 释放锁
this.mappingRegistry.releaseReadLock();
}
return var4;
}
该方法会通过lookupPath和request去匹配对应的处理器(controller里的方法)
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
// 根据路径获取路径匹配的所有规则。
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 将通过路径初次匹配的,去RequestMappingInfo中匹配,总共有七个规则匹配详情见下文#getMatchingCondition 方法
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 若上方没有找到匹配的,则将注册中心所有的映射拿去匹配
this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
// 找到了两个处理器,抛异常
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
该方法会将不匹配的信息过滤掉
@Nullable
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
// 请求方法过滤器
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
if (methods == null) {
return null;
} else {
// 请求参数过滤器
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
if (params == null) {
return null;
} else {
// 头字段过滤器
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
if (headers == null) {
return null;
} else {
// 请求媒体类型过滤器
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
if (consumes == null) {
return null;
} else {
// 应答媒体类型过滤器
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
if (produces == null) {
return null;
} else {
// 模式请求路径过滤器
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
} else {
// 自定义请求过滤器
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
return custom == null ? null : new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition());
}
}
}
}
}
}
}
在获取到处理器后,接着就是去获取处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
点开代码看看,看看细节。主要是循环当前所有的handlerAdapters,通过supports()判断是否支持当前handlerMethod,这种循环比对思想在Spring MVC源码随处可见。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
执行执行链中拦截器的前置方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 遍历拦截器
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
// 若拦截器返回false则终止
if (!interceptor.preHandle(request, response, this.handler)) {
// 释放资源
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
处理器适配器调用handle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
处理器调用handle方法后会进入AbstractHandlerMethodAdapter#handle 接着进入RequestMappingHandlerAdapter#handleInternal
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 检查请求
this.checkRequest(request);
ModelAndView mav;
// 根据session来判断是否需要加锁调用
if (this.synchronizeOnSession) {
// 获取session
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
// 执行处理器方法
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
调用处理器中的方法。需要构建参数,
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndView var15;
try {
// 获取数据绑定工厂 详情见 2.6.3
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
// 获取模型工厂 ModelFactory作用是在控制器方法调用前初始化Model模型,调用后对Model模型进行更新。
// 逻辑与获取数据绑定工厂差不多,先获取SessionAttributesHandler,再获取@ModelAttribute注解且没有被@RequestMapping注解的方法,最后构建出ModelFactory。
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
// 根据handlerMethod创建ServletInvocableHandlerMethod,ServletInvocableHandlerMethod用于对处理程序的返回值进行处理和ResponseStatus处理。
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 实例化ModelAndViewContainer容器,把request里面的属性名为"org.springframework.web.servlet.DispatcherServlet.INPUT_FLASH_MAP"的重定向参数注入到容器中的model模型中。FlashMap的作用是在redirect中传递参数。重定向是会生成新的request,那么传递参数就不能直接用request进行传递。
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 初始化数据模型容器,详情见2.6.4
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 处理一些异步请求
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
Object result;
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// ServletInvocableMethod中的invokeAndHandle()其实是间接调用handlerMethod,然后处理handlerMethod的返回值。详情见2.6.6
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (asyncManager.isConcurrentHandlingStarted()) {
result = null;
return (ModelAndView)result;
}
// 获取ModelAndView对象
var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
return var15;
}
该方法用于创建绑定工厂,先遍历全局的属性编辑器,被@ControllerAdvice里添加了@InitBinder注解的方法,再遍历controller类里添加了@InitBinder注解的方法,根据这些方法先生成InvocableHandlerMethod列表,再生成数据绑定工厂。
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
Class<?> handlerType = handlerMethod.getBeanType();
// 从initBinderCache缓存中获取该类的所有添加了 @InitBinder 注解的方法
Set<Method> methods = (Set)this.initBinderCache.get(handlerType);
if (methods == null) {
// 查询该类所有添加了@InitBinder 注解的方法并加入缓存
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList();
// 遍历被@ControllerAdvice注解全局类,methodSet中存放该类中添加了@InitBinder注解的方法
this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
Iterator var6 = methodSet.iterator();
while(var6.hasNext()) {
Method method = (Method)var6.next();
// 通过createInitBinderMethod(bean, method)方法创建InvocableHandlerMethod对象(用于参数准备,准备当中会用到WebDataBinderFactory创建WebDataBinder实例进行参数转换解析绑定,方法调用),并且放入到initBinderMethods集合中。
initBinderMethods.add(this.createInitBinderMethod(bean, method));
}
}
});
Iterator var5 = methods.iterator();
while(var5.hasNext()) {
Method method = (Method)var5.next();
Object bean = handlerMethod.getBean();
initBinderMethods.add(this.createInitBinderMethod(bean, method));
}
return this.createDataBinderFactory(initBinderMethods);
}
初始化模型,将添加了@ModelAttribute 的方法和参数添加了@ModelAttribute添加到模型中
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
throws Exception {
// 首先从request中获取检索@SessionAttribute中名称的属性,以Map的结构存储起来,并且放入到ModelAndViewContainer容器的model中。
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
// 合并到数据模型容器中
container.mergeAttributes(sessionAttributes);
// 调用模型属性方法来填充模型。只有在模型中不存在的情况下才会添加属性。详情见2.6.5
invokeModelAttributeMethods(request, container);
// 遍历参数中被@ModelAttribute的参数
// 在@SessionAttributes中找到@ModelAttribute参数。
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!container.containsAttribute(name)) {
// 从SessionAttributeStore中获取属性,不存在则返回空
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
}
container.addAttribute(name, value);
}
}
}
将添加了@ModelAttribute注解的方法返回值,添加到模型中
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
throws Exception {
while (!this.modelMethods.isEmpty()) {
InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
Assert.state(ann != null, "No ModelAttribute annotation");
// 模型中是否已经有了该属性,
if (container.containsAttribute(ann.name())) {
// 是否禁止绑定
if (!ann.binding()) {
container.setBindingDisabled(ann.name());
}
continue;
}
// 调用方法获取返回值
Object returnValue = modelMethod.invokeForRequest(request, container);
// 方法是否有返回值
if (!modelMethod.isVoid()){
// 获取返回值名称,其规则为:如果@ModelAttribute注解设置value和name属性了,优先选择value和name属性作为model中的key,如果没有设置value和name属性,选择被@ModelAttribute注解的handlerMethod的返回类型名称(首字母小写)作为model中的key。
// 注:若返回类型为列表或数组则,名称为 返回类型+List 如stringList
String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
if (!ann.binding()) {
container.setBindingDisabled(returnValueName);
}
if (!container.containsAttribute(returnValueName)) {
container.addAttribute(returnValueName, returnValue);
}
}
}
}
调用handlerMethod方法,并处理返回值
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 调用handlerMethod方法(controller里的方法),会先用InvocableHandlerMethod#getMethodArgumentValues()的方法获取所有参数数组,初始化参数。详情见2.6.7 。 参数解析完成后会通过反射调用方法
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
this.disableContentCachingIfNecessary(webRequest);
// 设置不需要驶入解析,例如@ResponseBody方法,因此不需要视图解析。当控制器方法声明ServletResponse或OutputStream类型的参数时,也可以设置此标志。
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 返回值处理,与前面的逻辑差不多,都是遍历所有的返回值处理器,判断是否支持该返回值类型,支持则调用处理器处理
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
InvocableHandlerMethod中的getMethodArgumentValues()这个方法是获取handlerMethod的参数。首先获取handlerMethod中的所有参数数组,数组类型是MethodParameter。遍历参数数组,给每一个参数初始化parameterNameDisconverer(参数名称发现器)。
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法参数数组
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 判断参数解析链是否支持parameter这种类型的参数解析。
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 遍历已注册的参数解析器解析参数,若找不到合适的解析器则抛出IllegalArgumentException异常
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
要么是ModelAndView,要么解析成ModelAndView的异常。如果异常不为空且是ModelAndViewDefiningException类型的异常,那么把视图解析成ModelAndViewDefiningException特定的视图。如果异常不为空且不是ModelAndViewDefiningException类型的异常,那么调用 processHandlerException()让HandlerExceptionResovlers中的异常处理器来处理。
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) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
// 将逻辑视图转换成真正的物理视图
this.render(mv, request, response);
// 是否已生成错误视图
if (errorView) {
// 清理错误属性(status_code、exception_type、message、exception、request_uri、servlet_name)
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}