🍅一、BasicErrorController
☘️1.1 描述
BasicErrorController是Springboot中默认的异常处理方法,无需额外的操作,当程序发生了异常之后,Springboot自动捕获异常,重新请求到BasicErrorController中,在BasicErrorController中返回一个视图页面。
🌱1.2 原理解析-配置
在ErrorMvcAutoConfiguration会配置Springboot中关于异常相关的类。其中有两个类是异常相关的。
1.2.1 BasicErrorController
配制的第一个Bean是BasicErrorController类,所有的异常捕获的时候,都会重新请求到这个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
初始化第二个Bean是ErrorPageCustomizer类,这个类是发生异常之后返回视图的模板页面
// 初始化一个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;
}
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
ErrorPage errorPage = new ErrorPage(
// 这里获取异常页面的路径,默认是在/error路径下面
this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
errorPageRegistry.addErrorPages(errorPage);
}
@Override
public 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,然后循环去调用ErrorViewResolver的resolveErrorView方法。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,在DefaultErrorViewResolver的resolverErrorView方法中先调用了resolve方法,这里传的参数是响应吗,比如500,404等。这个方法的目的是找到响应吗对应的页面比如500.html、404.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 {
@Override
public 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的原理要从DispatcherServlet的doDispatch开始,我们先看一下这个方法的主要流程,省略掉部分无关代码。先去执行对应请求的方法,如果方法里面发生异常捕获异常,无论是否发生异常都会执行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
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBodyAdvice beans
initExceptionHandlerAdviceCache();
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的原理要从DispatcherServlet的doDispatch开始,我们先看一下这个方法的主要流程,省略掉部分无关代码。先去执行对应请求的方法,如果方法里面发生异常捕获异常,无论是否发生异常都会执行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,只有DefaultErrorAttributes和HandlerExceptionResolverComposite。
这里先去调用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有三个ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver。
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;
}
首先调用的是ExceptionHandlerExceptionResolver的resolveException方法,但是这个方法没有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 well
Throwable 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 ArrayList
arguments[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中会调用HandlerExceptionResolverComposite的resolveException方法
5.在HandlerExceptionResolverComposite的resolveException方法会继续调用resolveExeption方法
6.这里是调用ExceptionHandlerExceptionResolver的resolveException方法
7.但是ExceptionHandlerExceptionResolver没有resolveException方法,但是它父类的父类AbstractHandlerExceptionResolver有这个方法
8.然后在resolveException中又调用了doResolveException方法,ExceptionHandlerExceptionResolver没有这个方法,但是它的父类有
9.在AbstractHandlerMethodExceptionResolver的doResolveException方法中调用了doResolveHandlerMethodException
10.doResolveHandlerMethodException是ExceptionHandlerExceptionResolver的,里面继续调用了getExceptionHandlerMethod方法
11.整个调用链路就完成了











