我是靠谱客的博主 饱满鸭子,最近开发中收集的这篇文章主要介绍错误处理原理(调试篇),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

      • DispatcherServlet#doDispatch
        • DispatcherServlet#processDispatchResult
          • DispatcherServlet#processHandlerException
      • DispatcherServlet#doDispatch
        • BasicErrorController#errorHtml
          • DefaultErrorAttributes#getErrorAttributes
          • AbstractErrorController#resolveErrorView
            • DefaultErrorViewResolver#resolve

DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//...
	try {
		Exception dispatchException = null;
		try {
			// Actually invoke the handler.
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);//本例:捕获异常,且继续抛出
	}
}

发送/divide请求,调用控制器方法处理该请求。
控制器方法在执行期间遇到异常时,当前请求会结束,且异常会被捕获,异常对象被保存到变量dispatchException中,然后执行processDispatchResult方法,它将处理异常。

DispatcherServlet#processDispatchResult

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable Exception exception) throws Exception {
	if (exception != null) {
		mv = processHandlerException(request, response, handler, exception);
	}
}

processHandlerException将处理控制器方法中发生的异常(本例:数学运算异常),处理完成后将返回ModelAndView实例mv。

DispatcherServlet#processHandlerException
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
		@Nullable Object handler, Exception ex) throws Exception {

	// Check registered HandlerExceptionResolvers...
	ModelAndView exMv = null;
	if (this.handlerExceptionResolvers != null) {
		for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
			exMv = resolver.resolveException(request, response, handler, ex);
			if (exMv != null) {
				break;
			}
		}
	}
	throw ex; //本例:异常被抛出
}

在这里插入图片描述
发送请求/divide,控制器方法IndexController#divide处理该请求,控制器方法执行过程中抛出异常:java.lang.ArithmeticException: / by zero。
遍历所有的HandlerExceptionResolver,看谁能处理当前异常。

处理器异常解析器有以下两类:

  1. DefaultErrorAttributes。
    DefaultErrorAttributes将异常对象保存到request域中,并返回null。
//DefaultErrorAttributes#resolveException
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
		Exception ex) {
		//把异常信息保存到request域并返回null
	storeErrorAttributes(request, ex);
	return null;
}
  1. HandlerExceptionResolverComposite。其中有:ExceptionHaExcepndlerExceptionResolver、ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver。
    @ExceptionHandler指定的异常,由ExceptionHaExcepndlerExceptionResolver解析处理;
    @ResponseStatus标注的异常,由ResponseStatusExceptionResolver解析处理;
    Spring底层的异常,由DefaultHandlerExceptionResolver解析处理。
//HandlerExceptionResolverComposite#resolveException
public ModelAndView resolveException(
		HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

	if (this.resolvers != null) {
		for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
			ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
			if (mav != null) {
				return mav;
			}
		}
	}
	return null;//本例:返回null
}
//AbstractHandlerExceptionResolver#resolveException
public ModelAndView resolveException(
		HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
	if (shouldApplyTo(request, handler)) {
		prepareResponse(ex, response);
		ModelAndView result = doResolveException(request, response, handler, ex); // 本例:result为null
		return result;
	}
}

遍历所有的异常解析器,希望找到能够处理当前异常的异常解析器。但是,遍历后发现:没有异常解析器能够处理当前异常。异常被抛出。

DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	// Determine handler for the current request.
	mappedHandler = getHandler(processedRequest);

	// Actually invoke the handler.
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

异常继续抛出,底层最终发送/error请求,且由BasicErrorController#errorHtml方法处理该请求(ErrorMvcAutoConfiguration自动配置实现)。
在这里插入图片描述

BasicErrorController#errorHtml

BasicErrorController#errorHtml方法处理/error请求。

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}
}
DefaultErrorAttributes#getErrorAttributes
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
	Map<String, Object> errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
	if (!options.isIncluded(Include.EXCEPTION)) {
		errorAttributes.remove("exception");
	}
	if (!options.isIncluded(Include.STACK_TRACE)) {
		errorAttributes.remove("trace");
	}
	if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
		errorAttributes.remove("message");
	}
	if (!options.isIncluded(Include.BINDING_ERRORS)) {
		errorAttributes.remove("errors");
	}
	return errorAttributes;
}

在这里插入图片描述

AbstractErrorController#resolveErrorView

resolveErrorView方法将解析错误视图。
遍历所有的错误视图解析器,看谁能解析。系统中默认只有一个错误视图解析器,即DefaultErrorViewResolver。

protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,
		Map<String, Object> model) {
	for (ErrorViewResolver resolver : this.errorViewResolvers) {
		ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
		if (modelAndView != null) {
			return modelAndView;
		}
	}
	return null;
}

在这里插入图片描述

DefaultErrorViewResolver#resolve

DefaultErrorViewResolver把响应状态码拼接为错误页面的地址,如"error/500.html"。

private ModelAndView resolve(String viewName, Map<String, Object> model) {
	String errorViewName = "error/" + viewName;
	TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
			this.applicationContext);
	if (provider != null) {
		return new ModelAndView(errorViewName, model);
	}
	return resolveResource(errorViewName, model);
}


//DefaultErrorViewResolver#resolveResource
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
	for (String location : this.resources.getStaticLocations()) {
		try {
			Resource resource = this.applicationContext.getResource(location);
			resource = resource.createRelative(viewName + ".html");
			if (resource.exists()) {
				return new ModelAndView(new HtmlResourceView(resource), model);
			}
		}
		catch (Exception ex) {
		}
	}
	return null;
}

在这里插入图片描述
在这里插入图片描述

最后

以上就是饱满鸭子为你收集整理的错误处理原理(调试篇)的全部内容,希望文章能够帮你解决错误处理原理(调试篇)所遇到的程序开发问题。

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

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

评论列表共有 0 条评论

立即
投稿
返回
顶部