我是靠谱客的博主 雪白麦片,最近开发中收集的这篇文章主要介绍由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方法:顾名思义,这里是处理转发结果的
	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...
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) throws Exception {// 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异常处理分析!所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部