ExceptionHandlerExceptionResolver源码分析

ExceptionHandlerExceptionResolver源码分析

与其说是分析异常处理器源码,倒不如是把Mvc自动配置走了一遍。
ExceptionHandlerExceptionResolver、RequestMappingHandlerMapping、RequestMappingHandlerAdapter的配置流程都是相似的。

自动配置

在WebMvcConfigurationSupport中,该类是Springboot自动配置Mvc最核心的类,完成了RequestHandlerMapping、Adapter、异常处理器、字符过滤器等等SSM中需要手动配置的部分,通常情况下,我们不需要自己直接配置该类,Mvc提供了MvcConfiure帮助我们自定义。
在AutoConfiguration中

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

可以看到,一旦我们向容器中注入了WebMvcConfigrationSupport,那我们又回到了手动配置Mvc的时候。
事实上,Springboot的AutoConfigration主要工作由EnableWebMvcConfiguration完成
该类继承自WebMvcConfigurationSupport,同时使用委托模式使Mvc配置可自义,具体可查看DelegatingWebMvcConfiguration。

@Bean
public HandlerExceptionResolver handlerExceptionResolver(
		@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
	List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
	/* 1. 自定义config */
	configureHandlerExceptionResolvers(exceptionResolvers);
	/* 2. 默认配置 */
	if (exceptionResolvers.isEmpty()) {
		addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
	}
	/* 3.扩展 */
	extendHandlerExceptionResolvers(exceptionResolvers);
	/* 4. 委托, */
	HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
	composite.setOrder(0);
	composite.setExceptionResolvers(exceptionResolvers);
	return composite;
}
  1. 优先自定义整个exceptionResolvers,这里会调用到我们编写的MvcConfigure配置类,如果结果不为空,SpringMvc认为我们有自定义配置,不再使用默认配置。
  2. 默认配置,会添加前面提到的三个Resolver。
  3. 扩展,这里会调用我们MvcConfigure的extendExption…方法
  4. 将三个Resolver委托。

addDefaultHandlerExceptionResolvers

/* 1. 此处支持自定义 */
ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
/* 2. 以下的getXXX方法都会使用到MvcConfigure中自定义的方法 */
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());
  1. 会优先委托WebMvcRegistrations实现,如果返回null,则使用默认
  2. 前面说过,Mvc自动配置依赖于EnableWebMvcConfiguration,这些getXXX方法都会被委托,添加自定义配置

异常处理器的初始化过程

扫描了所有ControllerAdvice注解的类,从该类扫描@ExceptionHandler注解,保存异常及对应的处理方法

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);
	}
	/* 真正解决异常的resolver */
	ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
	/* 如果在其中找到处理异常的方法 */
	if (resolver.hasExceptionMappings()) {
		this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
	}
	if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
		this.responseBodyAdvice.add(adviceBean);
	}
}

在ExceptionHandlerMethodResolver初始化方法中
handlerType即我们自定义全局异常处理器,扫描该全局处理器的所有被@ExceptionHandler注解的方法及其匹配的异常,并保存。
之后只需依据发生的异常,匹配到对应的方法即可。
匹配的时候,如果目标异常没有对应的方法,则尝试该异常的cause,如果没有,返回null

public ExceptionHandlerMethodResolver(Class<?> handlerType) {
	for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
		for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
			addExceptionMapping(exceptionType, method);
		}
	}
}

自定义配置异常处理器

ExceptionHandlerExceptionResolver部分属性

...
@Nullable
	private List<HandlerMethodArgumentResolver> customArgumentResolvers;

	@Nullable
	private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;

	private List<HttpMessageConverter<?>> messageConverters;

	private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();

	private final List<Object> responseBodyAdvice = new ArrayList<>();
...
  1. 自定义WebMvcConfigSupport,不推荐,需要配置整个Mvc

  2. 通过提供扩展接口

    • 参数解析器、返回值解析器、消息转换器、contentNegotiationManager,可通过MvcConfigure
    • responseBodyAdvice,通过ControllerAdive注解

    上两者都支持通过WebMvcRegistrations配置

RequestMappingHandlerMapping、RequestMappingHandlerAdapter配置方法也差不多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值