欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > springboot异常(三):异常处理原理

springboot异常(三):异常处理原理

2025/3/12 22:29:04 来源:https://blog.csdn.net/lhm964517471/article/details/142567371  浏览:    关键词:springboot异常(三):异常处理原理

🍅一、BasicErrorController

☘️1.1 描述

BasicErrorControllerSpringboot中默认的异常处理方法,无需额外的操作,当程序发生了异常之后,Springboot自动捕获异常,重新请求到BasicErrorController中,在BasicErrorController中返回一个视图页面。

🌱1.2 原理解析-配置

ErrorMvcAutoConfiguration会配置Springboot中关于异常相关的类。其中有两个类是异常相关的。

1.2.1 BasicErrorController

配制的第一个BeanBasicErrorController类,所有的异常捕获的时候,都会重新请求到这个Controller

@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,ObjectProvider<ErrorViewResolver> errorViewResolvers) {return new BasicErrorController(errorAttributes, this.serverProperties.getError(),                            errorViewResolvers.orderedStream().collect(Collectors.toList()));
}

1.2.2 ErrorPageCustomizer

初始化第二个BeanErrorPageCustomizer类,这个类是发生异常之后返回视图的模板页面

// 初始化一个ErrorPageCustomizer类
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
// ErrorPageCustomizer类主要的作用
static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {private final ServerProperties properties;private final DispatcherServletPath dispatcherServletPath;protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {this.properties = properties;this.dispatcherServletPath = dispatcherServletPath;}@Overridepublic void registerErrorPages(ErrorPageRegistry errorPageRegistry) {ErrorPage errorPage = new ErrorPage(// 这里获取异常页面的路径,默认是在/error路径下面this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));errorPageRegistry.addErrorPages(errorPage);}@Overridepublic int getOrder() {return 0;}
}

🌲1.3 原理解析-触发

当异常发生后会重新请求到BasicErrorController中,该类有两个接口一个是针对json的请求,一个是针对text/html的请求。这里主要看text/html的请求,返回一个ModelAndView。返回什么ModelAndView页面,是通过resolveErrorView方法去解析的。如果没有ModelAndView视图,就自己创建一个默认的返回。

// 处理针对请求是text/html的请求
@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);
}
// 处理请求是json的请求
@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);
}
  • resolveErrorView

这里先是获取所有的ErrorViewResolver,然后循环去调用ErrorViewResolverresolveErrorView方法。ErrorViewResolver是一个功能性接口,只有一个方法resolveErrorView

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

ErrorViewResolver只有一个实现类DefaultErrorViewResolver,在DefaultErrorViewResolverresolverErrorView方法中先调用了resolve方法,这里传的参数是响应吗,比如500404等。这个方法的目的是找到响应吗对应的页面比如500.html404.html等,如果没找到就找5xx.html页面。

@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {// 这里直接用500来解析是否有这个页面ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);// 如果是空的,就用5xx,去看看有没有这个页面if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;
}
  • resolve

resolve方法找到error路径下对应的页面,如果还是不存在就调用resolveResource方法去找。

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);
}
  • resolveResource

resolveResource方法先通过getStaticLocations()获取静态文件路径,然后去路径下判断是否有异常页面存在。

getStaticLocations()包含了四个路径:

1.classpath:/METAINF/resources/

2.classpath:/resources

3.classpath:/static/

4.classpath:/public/

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;}

🍇二、HandlerExceptionResolver

🌳1.1描述

HandlerExceptionResolver是通过定义一个类实现HandlerExceptionResolver接口,然后重写resolveException方法,这个方法返回一个ModelAndView类。在ModelAndView中可以定义一些异常相关的处理。

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {ModelAndView mv = new ModelAndView();mv.setViewName("error");mv.addObject("error", "报错了");mv.addObject("status", "saliwa");return mv;}
}

🌴1.2原理解析-触发

  • doDispatch

要解析HandlerExceptionResolver的原理要从DispatcherServletdoDispatch开始,我们先看一下这个方法的主要流程,省略掉部分无关代码。先去执行对应请求的方法,如果方法里面发生异常捕获异常,无论是否发生异常都会执行processDispatchResult

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {try {ModelAndView mv = null;Exception dispatchException = null;try {// 去执行我们要调用的方法,比如我们请求的某个controller方法,如果在这个controller执行过程中// 发生了异常或者错误都在这里捕获的,并且用dispatchException这个变量来接收返回的异常类mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {dispatchException = new NestedServletException("Handler dispatch failed", err);}// 这个方法无论是否有异常都会执行processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}}
  • processDispatchResult

processDispatchResult方法,这里省略部分无关代码,首先判读异常是否不为空,如果不为空就执行异常处理逻辑,调用processHandlerException方法。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;// 异常不为空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);}}
}
  • processHandlerException

这里主要是去找有没有HandlerExceptionResolver类,如果有,就执行他的resolveException方法,这个方法会返回ModelAndView,如果ModelAndView不为空就返回。

前面我们自定义的类就是实现了HandlerExceptionResolver接口,并且重写了resolveException方法,返回了一个ModelAndView,这里异常就处理结束了。

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,@Nullable Object handler, Exception ex) throws Exception {ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) {// 这里就是我们自己的实现类,包括两个默认的和我们自己定义的for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv = resolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {return exMv;}throw ex;
}

🍈三、ControllerAdvice

🌵3.1 描述

ControllerAdvice是全局异常拦截器,配合ExceptionHandler使用。除了可以拦截Java定义的异常,还可以自定义异常。

先自定义一个异常

@Getter
@Setter
public class MyException extends RuntimeException {private String errorCode;private String errorMessage;public MyException () {super();}public MyException(String errorCode, String errorMessage) {super(errorMessage);this.errorCode = errorCode;this.errorMessage = errorMessage;}
}

自定义一个全局异常拦截器,拦截自定义的异常和空指针异常。

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {// 自定异常@ExceptionHandler(value = MyException.class)public Object restErrorHandler(HttpServletRequest request, MyException e) {log.error("报错了: ", e);return "错误码:" + e.getErrorCode() + "错误内容:" + e.getErrorMessage();}// 空指针异常@ExceptionHandler(value={java.lang.NullPointerException.class})public String nullPointerExceptionHandler(Exception e){log.error("报错了 ", e);return "错误内容:" + e.getMessage();}
}

🌾3.2 原理解析-配置

3.2.1 WebMvcConfigurationSupport

  • handlerExceptionResolver

WebMvcConfigurationSupport类里面要初始化一个HandlerExceptionResolver类,在初始化这个类之后要,要执行addDefaultHandlerExceptionResolvers方法。

@Bean
public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();configureHandlerExceptionResolvers(exceptionResolvers);if (exceptionResolvers.isEmpty()) {addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);}extendHandlerExceptionResolvers(exceptionResolvers);HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();composite.setOrder(0);composite.setExceptionResolvers(exceptionResolvers);return composite;
}
  • addDefaultHandlerExceptionResolvers

在这个方法里面先调用了createExceptionHandlerExceptionResolver方法创建了ExceptionHandlerExceptionResolver类。

protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers,ContentNegotiationManager mvcContentNegotiationManager) {ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);exceptionHandlerResolver.setMessageConverters(getMessageConverters());exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());if (jackson2Present) {exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));}if (this.applicationContext != null) {exceptionHandlerResolver.setApplicationContext(this.applicationContext);}exceptionHandlerResolver.afterPropertiesSet();exceptionResolvers.add(exceptionHandlerResolver);ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();responseStatusResolver.setMessageSource(this.applicationContext);exceptionResolvers.add(responseStatusResolver);exceptionResolvers.add(new DefaultHandlerExceptionResolver());}

3.2.2 ExceptionHandlerExceptionResolver

  • afterPropertiesSet

在这个方法里面主要是调用了一个方法initExceptionHandlerAdviceCache

@Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beansinitExceptionHandlerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}
  • initExceptionHandlerAdviceCache

这个方法是最重要的,首先获取有ControllerAdvice这个注解的bean,也就是我们自定义的全局异常拦截器,然后将这个bean转换成ExceptionHandlerMethodResolver

private void initExceptionHandlerAdviceCache() {if (getApplicationContext() == null) {return;}// 获取有ControllerAdvice注解的类List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();if (beanType == null) {throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);}ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {this.responseBodyAdvice.add(adviceBean);}}if (logger.isDebugEnabled()) {int handlerSize = this.exceptionHandlerAdviceCache.size();int adviceSize = this.responseBodyAdvice.size();if (handlerSize == 0 && adviceSize == 0) {logger.debug("ControllerAdvice beans: none");}else {logger.debug("ControllerAdvice beans: " +handlerSize + " @ExceptionHandler, " + adviceSize + " ResponseBodyAdvice");}}}

🌿3.3 原理解析-触发

3.3.1 DispatcherServlet

  • doDispatch

要解析HandlerExceptionResolver的原理要从DispatcherServletdoDispatch开始,我们先看一下这个方法的主要流程,省略掉部分无关代码。先去执行对应请求的方法,如果方法里面发生异常捕获异常,无论是否发生异常都会执行processDispatchResult

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {try {ModelAndView mv = null;Exception dispatchException = null;try {// 去执行我们要调用的方法,比如我们请求的某个controller方法,如果在这个controller执行过程中// 发生了异常或者错误都在这里捕获的,并且用dispatchException这个变量来接收返回的异常类mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {dispatchException = new NestedServletException("Handler dispatch failed", err);}// 这个方法无论是否有异常都会执行processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}}
  • processDispatchResult

processDispatchResult方法,这里省略部分无关代码,首先判读异常是否不为空,如果不为空就执行异常处理逻辑,调用processHandlerException方法。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;// 异常不为空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);}}
}
  • processHandlerException

这里主要是去找有没有HandlerExceptionResolver类,如果有,就执行他的resolveException方法,这个方法会返回ModelAndView,如果ModelAndView不为空就返回。

这里我们没有自定义HandlerExceptionResolver,只有DefaultErrorAttributesHandlerExceptionResolverComposite

这里先去调用DefaultErrorAttributes的resolverException方法,这个方法返回的是null,然后会继续调用HandlerExceptionResolverComposite类的resolverException方法。

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,@Nullable Object handler, Exception ex) throws Exception {ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) {for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv = resolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {return exMv;}throw ex;
}

3.3.2 HandlerExceptionResolverComposite

  • resolveException

在这个方法里面会继续找HandlerExceptionResolver,并执行resolve Exception方法。这里的HandlerExceptionResolver有三个ExceptionHandlerExceptionResolverResponseStatusExceptionResolverDefaultHandlerExceptionResolver

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;
}

首先调用的是ExceptionHandlerExceptionResolverresolveException方法,但是这个方法没有resolveException方法,但是它的抽象父类的父类AbstractHandlerExceptionResolver有这个方法

3.3.3AbstractHandlerExceptionResolver

  • resolveException

这里的resolveException方法中,调用了doResolveException去获取ModelAndView

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);if (result != null) {// Print debug message when warn logger is not enabled.if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));}// Explicitly configured warn logger in logException method.logException(ex, request);}return result;}else {return null;}
}
  • doResolveException

ExceptionHandlerExceptionResolver也没有 doResolveException但是它的父类AbstractHandlerMethodExceptionResolver有这个方法。

3.3.4 AbstractHandlerMethodExceptionResolver

  • doResolveException

这里走的是AbstractHandlerMethodExceptionResolver类的doResolveException方法,这个方法会继续调用doResolveHandlerMethodException,这个方法是在ExceptionHandlerExceptionResolver里面。

@Override
@Nullable
protected final ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null);return doResolveHandlerMethodException(request, response, handlerMethod, ex);
}

3.3.5 ExceptionHandlerExceptionResolver

  • doResolveHandlerMethodException

看下ExceptionHandlerExceptionResolver实现的doResolveHandlerMethodException,这里最重要的是第一行getExceptionHandlerMethod,获取异常处理方法

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);if (exceptionHandlerMethod == null) {return null;}if (this.argumentResolvers != null) {exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers != null) {exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}ServletWebRequest webRequest = new ServletWebRequest(request, response);ModelAndViewContainer mavContainer = new ModelAndViewContainer();ArrayList<Throwable> exceptions = new ArrayList<>();try {if (logger.isDebugEnabled()) {logger.debug("Using @ExceptionHandler " + exceptionHandlerMethod);}// Expose causes as provided arguments as wellThrowable exToExpose = exception;while (exToExpose != null) {exceptions.add(exToExpose);Throwable cause = exToExpose.getCause();exToExpose = (cause != exToExpose ? cause : null);}Object[] arguments = new Object[exceptions.size() + 1];exceptions.toArray(arguments);  // efficient arraycopy call in ArrayListarguments[arguments.length - 1] = handlerMethod;exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);}catch (Throwable invocationEx) {// Any other than the original exception (or a cause) is unintended here,// probably an accident (e.g. failed assertion or the like).if (!exceptions.contains(invocationEx) && logger.isWarnEnabled()) {logger.warn("Failure in @ExceptionHandler " + exceptionHandlerMethod, invocationEx);}// Continue with default processing of the original exception...return null;}if (mavContainer.isRequestHandled()) {return new ModelAndView();}else {ModelMap model = mavContainer.getModel();HttpStatus status = mavContainer.getStatus();ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);mav.setViewName(mavContainer.getViewName());if (!mavContainer.isViewReference()) {mav.setView((View) mavContainer.getView());}if (model instanceof RedirectAttributes) {Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);}return mav;}}
  • getExceptionHandlerMethod

可以看出这里是先找到有ControllerAdvicebean的类,然后根据异常类型去匹配这个bean里面定义的ExceptionHandler,这里就找到我们自己定义的全局异常处理的ExceptionHandler,进行异常处理。

protected ServletInvocableHandlerMethod getExceptionHandlerMethod(@Nullable HandlerMethod handlerMethod, Exception exception) {Class<?> handlerType = null;if (handlerMethod != null) {// Local exception handler methods on the controller class itself.// To be invoked through the proxy, even in case of an interface-based proxy.handlerType = handlerMethod.getBeanType();ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);if (resolver == null) {resolver = new ExceptionHandlerMethodResolver(handlerType);this.exceptionHandlerCache.put(handlerType, resolver);}Method method = resolver.resolveMethod(exception);if (method != null) {return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);}// For advice applicability check below (involving base packages, assignable types// and annotation presence), use target class instead of interface-based proxy.if (Proxy.isProxyClass(handlerType)) {handlerType = AopUtils.getTargetClass(handlerMethod.getBean());}}for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {ControllerAdviceBean advice = entry.getKey();if (advice.isApplicableToBeanType(handlerType)) {ExceptionHandlerMethodResolver resolver = entry.getValue();Method method = resolver.resolveMethod(exception);if (method != null) {return new ServletInvocableHandlerMethod(advice.resolveBean(), method);}}}return null;
}

3.3.6 调用时序图

这里的整体调用逻辑如下:

1.首先调用dispatch去执行方法执行目标方法

2.执行完毕之后调用processDispatchResult去处理执行结果

3.如果目标方法抛出了一场就执行processHandlerException去处理异常

4.在processHandlerException中会调用HandlerExceptionResolverCompositeresolveException方法

5.在HandlerExceptionResolverCompositeresolveException方法会继续调用resolveExeption方法

6.这里是调用ExceptionHandlerExceptionResolverresolveException方法

7.但是ExceptionHandlerExceptionResolver没有resolveException方法,但是它父类的父类AbstractHandlerExceptionResolver有这个方法

8.然后在resolveException中又调用了doResolveException方法,ExceptionHandlerExceptionResolver没有这个方法,但是它的父类有

9.在AbstractHandlerMethodExceptionResolverdoResolveException方法中调用了doResolveHandlerMethodException

10.doResolveHandlerMethodExceptionExceptionHandlerExceptionResolver的,里面继续调用了getExceptionHandlerMethod方法

11.整个调用链路就完成了

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词