概述
文章目录
- 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,看谁能处理当前异常。
处理器异常解析器有以下两类:
- DefaultErrorAttributes。
DefaultErrorAttributes将异常对象保存到request域中,并返回null。
//DefaultErrorAttributes#resolveException
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
//把异常信息保存到request域并返回null
storeErrorAttributes(request, ex);
return null;
}
- 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;
}
最后
以上就是饱满鸭子为你收集整理的错误处理原理(调试篇)的全部内容,希望文章能够帮你解决错误处理原理(调试篇)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复