SpringMVC源码分析(三)HandlerExceptionResolver启动和异常处理源码分析

问题:异常处理器在SpringMVC中是如何进行初始化以及使用的?

Spring MVC提供处理异常的方式主要分为两种:
1、实现HandlerExceptionResolver方式(HandlerExceptionResolver是一个接口,在SpringMVC有一些默认的实现也可以自定义异常处理器)
2、@ExceptionHandler注解方式。注解方式也有两种用法:
(1)使用在Controller内部
(2)配置@ControllerAdvice一起使用实现全局处理
下面的HandlerExceptionResolver接口的类的继承关系。

SpringMVC源码分析(三)HandlerExceptionResolver启动和异常处理源码分析_第1张图片
SpringMVC源码分析(三)HandlerExceptionResolver启动和异常处理源码分析_第2张图片

补充说明:注解@EnableWebMvc和

这个注解得作用就是相当于再配置文件中加上 本质都是会默认得注入一些SpringMVC得核心组件,比如RequestMappingHandlerMapping与RequestMappingHandlerAdapter等,而@EnableWebMvc注解 也是一样得作用默认得会加载一些组件。@EnableWebMvc通常是加载配置类上使用的,在初始化父容器的时候会进行注解的解析然后装载默认组件。
不过SpringMVC中如果配置了 mvc:annotation-driven/ 或者使用了@EnableWebMvc就会引入的 HandlerExceptionResolverComposite,这个是包含ExceptionHandlerExceptionResolver、DefaultHandlerExceptionResolver、ResponseStatusExceptionResolver3个处理器的是一个组合模式,下面会涉及到这个

一、启动源码分析

0、DispatcherServlet#initStrategies()

回归到DispatcherServlet在执行初始化策略中,跳过其他看initHandlerExceptionResolvers(context)

    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }

1 initHandlerExceptionResolvers()

找到类是HandlerExceptionResolver的Bean,加入到handlerExceptionResolvers,如果没有的话,就用默认的。这里的默认是会取读取DispatcherServlet.properties

private void initHandlerExceptionResolvers(ApplicationContext context) {
        this.handlerExceptionResolvers = null;

        if (this.detectAllHandlerExceptionResolvers) {
            // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
                    .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
                // We keep HandlerExceptionResolvers in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
            }
        }
        else {
            try {
                HandlerExceptionResolver her =
                        context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
                this.handlerExceptionResolvers = Collections.singletonList(her);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, no HandlerExceptionResolver is fine too.
            }
        }

        // Ensure we have at least some HandlerExceptionResolvers, by registering
        // default HandlerExceptionResolvers if no other resolvers are found.
        if (this.handlerExceptionResolvers == null) {
            this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
            if (logger.isTraceEnabled()) {
                logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
                        "': using default strategies from DispatcherServlet.properties");
            }
        }
    }

1.1 配置文件:DispatcherServlet.properties

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

1.2 getDefaultStrategies()

如果容器中获取不到 ,就是在使用了@EnableWebMvc和后加载的默认的组件还是获取不到的话,就会从DispatcherServlet.properties中加载默认的异常处理器。

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
							"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
							className + "] for interface [" + key + "]", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<>();
		}
	}
1.2.1 createDefaultStrategy()

SpringMVC中的几个默认的异常处理器就是经过这个方法,但是这个方式创建出来的bean对象是不归Spring管理的。

protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
		return context.getAutowireCapableBeanFactory().createBean(clazz);
	}

0、常见的默认异常处理器

1 SimpleMappingExceptionResolver

基本不用刻意忽略

2 ResponseStatusExceptionResolver

用于处理通过@ResponseStatus注解处理的异常

// 实现了接口MessageSourceAware,方便拿到国际化资源,方便错误消息的国际化
// @since 3.0
public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {

	@Nullable
	private MessageSource messageSource;
	@Override
	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}


	@Override
	@Nullable
	protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
		try {
			// 若异常类型是,那就处理这个异常
			// 处理很简单:response.sendError(statusCode, resolvedReason)
			// 当然会有国际化消息的处理。最终new一个空的new ModelAndView()供以返回
			if (ex instanceof ResponseStatusException) {
				return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler);
			}

			// 若异常类型所在的类上标注了ResponseStatus注解,就处理这个状态码
			//(可见:异常类型优先于ResponseStatus)
			// 处理方式同上~~~~
			ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
			if (status != null) {
				return resolveResponseStatus(status, request, response, handler, ex);
			}

			// 这里有个递归:如果异常类型是Course里面的,也会继续处理,所以需要注意这里的递归处理
			if (ex.getCause() instanceof Exception) {
				return doResolveException(request, response, handler, (Exception) ex.getCause());
			}
		} catch (Exception resolveEx) { // 处理失败,就记录warn日志(非info哦~)
			if (logger.isWarnEnabled()) {
				logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", resolveEx);
			}
		}
		return null;
	}
}

3 DefaultHandlerExceptionResolver

用于处理Spring MVC自己抛出的一些特定的异常

异常类型 状态码
MissingPathVariableException 500
ConversionNotSupportedException 500
HttpMessageNotWritableException 500
AsyncRequestTimeoutException 503
MissingServletRequestParameterException 400
ServletRequestBindingException 400
TypeMismatchException 400
HttpMessageNotReadableException 400
MethodArgumentNotValidException 400
MissingServletRequestPartException 400
BindException 400
NoHandlerFoundException 404
HttpRequestMethodNotSupportedException 405
HttpMediaTypeNotAcceptableException 406
HttpMediaTypeNotSupportedException 415
// @since 3.0
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
	public DefaultHandlerExceptionResolver() {
		setOrder(Ordered.LOWEST_PRECEDENCE);
		setWarnLogCategory(getClass().getName()); // 不同的日志采用不同的记录器是个很好的习惯
	}

	@Override
	@Nullable
	protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
		try {
			if (ex instanceof HttpRequestMethodNotSupportedException) {
				return handleHttpRequestMethodNotSupported(
						(HttpRequestMethodNotSupportedException) ex, request, response, handler);
			} else if (ex instanceof HttpMediaTypeNotSupportedException) {
				return handleHttpMediaTypeNotSupported(
						(HttpMediaTypeNotSupportedException) ex, request, response, handler);
			} ... // 省略其它的else if
			// 多有的handle方法几乎一样的,都是response.sendError()
			// 有的还会esponse.setHeader("Accept", MediaType.toString(mediaTypes));等等
	}
}

4 ExceptionHandlerExceptionResolver

用于处理通过@ExceptionHandler注解处理的方法抛出的异常,这个异常处理器是用的最多的。

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
		implements ApplicationContextAware, InitializingBean {
		。。。。。。。。。。
}

4.0 ExceptionHandlerExceptionResolver

继承自AbstractHandlerMethodExceptionResolver,该类主要处理Controller中用@ExceptionHandler注解定义的方法。
该类也是配置中定义的HandlerExceptionResolver实现类之一,大多数异常处理都是由该类操作。
SpringMVC中如果配置了 mvc:annotation-driven/ 或者就会引入的 HandlerExceptionResolverComposite,
SpringMVC源码分析(三)HandlerExceptionResolver启动和异常处理源码分析_第3张图片
1、argumentResolvers和customArgumentResolvers是参数解析器,负责将HTTP请求数据解析成异常处理方法的形参对象。

2、returnValueHandlers和customReturnValueHandlers是返回值处理器,负责将异常处理方法的返回值进行处理。

3、messageConverters是数据转换的底层工具,一方面从HTTP请求中读取并转换数据成对象,另一方面将对象转成HTTP响应数据。

4、contentNegotiationManager是负责媒体内容的校验,即根据Content-Tepe进行不同处理。

5、responseBodyAdvice是ResponseBodyAdvice的缓存,即支持在异常处理返回值写到输出流前的切面处理。

6、applicationContext是Spring上下文,可以从中获取容器中内容。

7、exceptionHandlerCache是异常-异常处理方法的缓存。

8、exceptionHandlerAdviceCache是@ControllerAdvice全局异常处理器的缓存。

4.1 afterPropertiesSet()

在创建这个ExceptionHandlerExceptionResolver对象的时候会执行他的afterPropertiesSet(),在这方法中会去获取@ControllerAdvice定义的全局ExceptionHandler方法

	@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBodyAdvice beans
		//初始化 @ControllerAdvice 的 bean
		initExceptionHandlerAdviceCache();

		if (this.argumentResolvers == null) {
			//获取 默认的参数解析器 DefaultArgumentResolvers
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		if (this.returnValueHandlers == null) {
			//获取 默认的返回值处理器 DefaultReturnValueHandlers
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}
4.1.1 initExceptionHandlerAdviceCache()

在nitExceptionHandlerAdviceCache()方法中,会从Spring容器中获取所有@ControllerAdvice标注的bean。遍历这些bean,将其中@ExceptionHandler标注的异常处理方法缓存到exceptionHandlerAdviceCache。如果这些bean实现了ResponseBodyAdvice接口,还会缓存到responseBodyAdvice:

private void initExceptionHandlerAdviceCache() {  
   // 获取所有@ControllerAdvice标注的bean
   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);  
      // 添加exceptionHandlerAdviceCache缓存
      if (resolver.hasExceptionMappings()) {  
         this.exceptionHandlerAdviceCache.put(adviceBean, resolver);  
      }  
      // 添加responseBodyAdvice缓存
      if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {  
         this.responseBodyAdvice.add(adviceBean);  
      }  
   }   
}

4.2 getDefaultArgumentResolvers()

protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

		// Annotation-based argument resolution
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());

		// Custom arguments
		//合并了自定义的参数解析器
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new PrincipalMethodArgumentResolver());

		return resolvers;
	}

4.3 getDefaultReturnValueHandlers()

获取返回值处理器,自此对象创建完成。

protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
		List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();

		// Single-purpose return value types
		handlers.add(new ModelAndViewMethodReturnValueHandler());
		handlers.add(new ModelMethodProcessor());
		handlers.add(new ViewMethodReturnValueHandler());
		handlers.add(new HttpEntityMethodProcessor(
				getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));

		// Annotation-based return value types
		handlers.add(new ServletModelAttributeMethodProcessor(false));
		handlers.add(new RequestResponseBodyMethodProcessor(
				getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));

		// Multi-purpose return value types
		handlers.add(new ViewNameMethodReturnValueHandler());
		handlers.add(new MapMethodProcessor());

		// Custom return value types
		//合并了自定义的返回值处理器
		if (getCustomReturnValueHandlers() != null) {
			handlers.addAll(getCustomReturnValueHandlers());
		}

		// Catch-all
		handlers.add(new ServletModelAttributeMethodProcessor(true));

		return handlers;
	}

二、异常处理流程源码分析

1、DispatcherServlet#processDispatchResult()

在DispatcherServlet#doDispatch()处理请求过程中抛出异常,会在DispatcherServlet#processDispatchResult()方法中进行异常处理, 如果监测到了非ModelAndViewDefiningException异常,会调用DispatcherServlet#processHandlerException()方法进行异常处理:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
   try {    
      try {  
         // 文件请求处理
         processedRequest = checkMultipart(request);  
         // 请求地址映射
         mappedHandler = getHandler(processedRequest);  
         // 获取处理器适配器
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
         // 拦截器预处理
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
            return;  
         }  
         // 实际处理请求
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
         // 拦截器后处理
         mappedHandler.applyPostHandle(processedRequest, response, mv);  
      }  
      catch (Exception ex) {  
         dispatchException = ex;  
      }  
      catch (Throwable err) {  
         // As of 4.3, we're processing Errors thrown from handler methods as well,  
         // making them available for @ExceptionHandler methods and other scenarios.         dispatchException = new NestedServletException("Handler dispatch failed", err);  
      }  
      // 异常处理
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
   }  
}

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,  
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,  
      @Nullable Exception exception) throws Exception {  
   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);  
      }  
   }  
}

2、processHandlerException()

由于默认初始化添加的是HandlerExceptionResolverComposite处理器,所以执行的也是当前类的resolveException();

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

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

2.1.1 AbstractHandlerExceptionResolver的resolveException()

先会调用其父类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);  
      if (result != null) {  
         // Print debug message when warn logger is not enabled.  
         if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {  
            logger.debug(buildLogMessage(ex, request) + (result.isEmpty() ? "" : " to " + result));  
         }  
         // Explicitly configured warn logger in logException method.  
         logException(ex, request);  
      }  
      return result;  
   }  
   else {  
      return null;  
   }  
}

2.1.1.1 AbstractHandlerMethodExceptionResolver#doResolveException()

进行类型转换

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

2.1.1.1.1ExceptionHandlerExceptionResolver#doResolveHandlerMethodException()

从缓存中获取异常对应的处理方法,添加argumentResolvers和returnValueHandlers。解析异常作为请求参数,最后调用异常处理方法进行异常处理。

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,  
      HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {    
   // 从缓存中获取异常对应的处理方法
   ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);  
   if (exceptionHandlerMethod == null) {  
      return null;  
   }  
  
   // 添加argumentResolvers和returnValueHandlers
   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) {  
      return null;  
   }  
   if (mavContainer.isRequestHandled()) {  
      return new ModelAndView();  
   }  
}

其中ExceptionHandlerExceptionResolver#getExceptionHandlerMethod方法,根据request请求的方法和抛出的异常可以匹配到对应的handleMethod。getExceptionHandlerMethod这个方法可以支持单独使用@ExceptionHandler,既使用了@ExceptionHandler又使用了@ControllerAdvice两种方式。
在ExceptionHandlerExceptionResolver#initExceptionHandlerAdviceCache方法中,ExceptionHandlerExceptionResolver已经扫描了所有@ControllerAdvice注解的Bean,并将其封装成了一个又一个的ExceptionHandlerMethodResolver,而构造ExceptionHandlerMethodResolver时,ExceptionHandlerMethodResolver就会扫描这个Bean下所有的@ExceptionHandler注解的方法。
所以可以先匹配这个controller是否有使用@ExceptionHandler,如果没有,则从缓存的ControllerAdviceBean中匹配异常。

2.1.1.1.1.1 ServletInvocableHandlerMethod#getExceptionHandlerMethod()
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
    //得到controller
    Class<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null);

    if (handlerMethod != null) {
        //先尝试从缓存中获取ExceptionHandlerMethodResolver
        //ExceptionHandlerMethodResolver有缓存所有`@ExceptionHandler`注解的方法
        ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
        if (resolver == null) {
            //没获取到的话,构造一个并将其放入缓存中
            resolver = new ExceptionHandlerMethodResolver(handlerType);
            this.exceptionHandlerCache.put(handlerType, resolver);
        }
        //根据异常获取对应的handler_method
        //如果不为空,则说明这个controoler配置了`@ExceptionHandler`
        Method method = resolver.resolveMethod(exception);
        if (method != null) {
            return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
        }
    }

    //如果controller没有配置`@ExceptionHandler`,则使用统一配置的`@ControllerAdvice`
    //遍历所有的`@ControllerAdvice`,根据异常匹配对应的handler_method
    for (Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {
        if (entry.getKey().isApplicableToBeanType(handlerType)) {
            ExceptionHandlerMethodResolver resolver = entry.getValue();
            Method method = resolver.resolveMethod(exception);
            //如果匹配倒了,返回这个method
            if (method != null) {
                return new ServletInvocableHandlerMethod(entry.getKey().resolveBean(), method);
            }
        }
    }

    return null;
}

2.1.1.1.1.2 ServletInvocableHandlerMethod#invokeAndHandle()

和之前的HandleMapping一眼的处理流程

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {

    //调用反射handler_method,拿到handler_method执行的结果`returnValue`
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    //如果这个handler_method上,还标注了`@ResponseStatus`注解
    //设置response的http状态码和错误原因
    setResponseStatus(webRequest);

    //将执行结果保存到ModelAndViewContainer中
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(this.responseReason)) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    try {
        //处理执行的返回值
        this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
        }
        throw ex;
    }
}

3、总结流程

1、ExceptionHandlerExceptionResolver根据请求的方法和抛出的异常,匹配对应的异常处理方法
2、先匹配controller中有的@ExceptionHandler标注了的方法
3、再匹配@ControllerAdvice中的@ExceptionHandler标注的方法
4、执行异常处理方法,获取返回值
5、返回值输出到response中

你可能感兴趣的:(SSM,SpringBoot源码分析,spring,java,mvc)