我是靠谱客的博主 雪白麦片,最近开发中收集的这篇文章主要介绍由HandlerInterceptor.afterCompletion引起的对DispatcherServlet异常处理分析!,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
该方法的签名:
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
该方法 最后一个参数为异常信息,但是我在Controller中throw异常,页面都提示了,我却在这个方法中获取不到,WHY?看下面代码注释!
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.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); // 当请求结束后,会调用该方法,并把异常传到该方法
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex); // NOTE!!!
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
processDispatchResult方法:顾名思义,这里是处理转发结果的protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) throws Exception {// Check registered HandlerExceptionResolvers...// 在这里获得异常处理的页面private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; // 先判断刚才传过来的是否有异常 if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { // 页面异常和我们所需的无关,一般是你JSP语法写错之类的 logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception);// 主要是这里,在这里获得你处理异常后返回的页面(<span style="color:#808000;">@ExceptionHandler的处理返回页面,或者XML配置文件中的页面</span>) errorView = (mv != null); } } // 获得到页面后进行渲染 if (mv != null && !mv.wasCleared()) { 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; } // 如果方法不是空,则执行触发afterCompletion方法,可以看到,第三个参数是NULL,所以我们需要的Exception没传!! if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
根据上面的注释,一切看起来都是很正常的,然而我们在拦截器中的afterCompletion就是获取不到Exception信息。
关在在这个函数:processHandlerException<pre style="background-color:#ffffff;color:#000000;font-family:'Consolas';font-size:10.5pt;"><pre name="code" class="java"> // Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}if (exMv != null) { // 如果有页面,那么进行一些处理然后返回该页面!!!注意下面的throw ex就执行不到了!if (exMv.isEmpty()) {return null;}// We might still need view name translation for a plain error model...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; // 如果没有页面,就throw}
从此我们可以看到,如果定义了页面异常处理返回的页面,那么我们在拦截器就获取不到Exception,因为在doDispath方法中没有执行
triggerAfterCompletion(processedRequest, response, mappedHandler, ex); // NOTE!!!
猜测可能是Spring觉得你既然已经自己处理了异常,那么这里就不给你传过去了。。。
然而DispatchServlet的源码还是不能改的,也不能用继承来扩展。
最后
以上就是雪白麦片为你收集整理的由HandlerInterceptor.afterCompletion引起的对DispatcherServlet异常处理分析!的全部内容,希望文章能够帮你解决由HandlerInterceptor.afterCompletion引起的对DispatcherServlet异常处理分析!所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复