SpringMVC执行流程,源码分析(三)
后置处理器
/* 参见异步的文章 */
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
/* 后置处理器 */
mappedHandler.applyPostHandle(processedRequest, response, mv);
处理结果
request的处理结果以及该请求过程中可能发生的异常
如果发生了异常
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);
}
}
可以看到,一旦某个异常处理器返回了视图,后续的异常处理器都不会被调用
默认有两个HandlerExceptionResolver
- DefaultErrorAttributes,将异常保存到域中,返回null
- HandlerExceptionResolverComposite,委托给另外三个resolver实现
- ExceptionHandlerExceptionResolver,通常说的全局异常处理器,Spring启动时,会扫描ControllerAdvice注解,然后收集其中的异常与对应的处理方法。
我们指定的全局异常处理器的方法,其实和控制器的方法差不多,走的执行流程也相似。 - ResponseStatusExceptionResolver,要处理的异常被@ResponseStatus注解,调用该处理器
if (ex instanceof ResponseStatusException) { return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler); } ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class); if (status != null) { return resolveResponseStatus(status, request, response, handler, ex); } if (ex.getCause() instanceof Exception) { return doResolveException(request, response, handler, (Exception) ex.getCause()); }
- DefaultHandlerExceptionResolver,当上面处理器都没能处理异常后,走默认处理逻辑,类似我们看到的tomcat的默认蓝色的错误页或者白色一堆报错或者json格式,依据客户端Accept而定,该处理器就是一堆if else判断异常原因,返回视图
- ExceptionHandlerExceptionResolver,通常说的全局异常处理器,Spring启动时,会扫描ControllerAdvice注解,然后收集其中的异常与对应的处理方法。
处理视图
如果此时视图不为null,可能是未发生异常或者处理异常后返回了视图
如果视图为null,那么返回的内容不是视图
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
在render函数中,模板引擎开始工作
拦截器-已完成
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
至此,拦截器三个方法都被调用了。
到此,差不多分析完成了,略过了很多异步的内容,打算单独写一篇文章分析
Q.E.D.