Spring 全局异常处理
首先需要确定的是,并没有用到 动态代理 。
请求被全局异常处理的过程
DispatcherServlet.class
请求进入DispatcherServlet#doDispatch方法中,如果出现参数缺失,异常类型=NoResourceFoundException。
HandlerExceptionResolverComposite.class
异常信息一直传递到HandlerExceptionResolverComposite.class#resolveException中,此时会遍历resolvers进行处理,如下图:

ExceptionHandlerExceptionResolver.class
异常信息传递到ExceptionHandlerExceptionResolver.class#doResolveHandlerMethodException
java
// 这里会寻找开发写的@ExceptionHandle(某种异常.class),异常的种类如果是exception的父类或者同样的类算作匹配并返回对应的异常处理方法
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
...
// 调用开发写的全局异常处理方法
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
有关内容在启动时的处理
D:\JavaKFHJ\repository\org\springframework\spring-webmvc\6.1.6\spring-webmvc-6.1.6.jar!\org\springframework\web\servlet\config\annotation\WebMvcConfigurationSupport.class#handlerExceptionResolver注册一个名为"handlerExceptionResolver"的bean,如下:
java
@Bean
public HandlerExceptionResolver handlerExceptionResolver(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
// 经过这一步处理后exceptionResolvers的长度变成了3
addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
D:\JavaKFHJ\repository\org\springframework\spring-webmvc\6.1.6\spring-webmvc-6.1.6.jar!\org\springframework\web\servlet\config\annotation\WebMvcConfigurationSupport.class#addDefaultHandlerExceptionResolvers,在这个方法的代码中创建了3个HandlerExceptionResolver,如下:
java
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());
}
以exceptionHandlerResolver.afterPropertiesSet();作为调用入口,调用D:\JavaKFHJ\repository\org\springframework\spring-webmvc\6.1.6\spring-webmvc-6.1.6.jar!\org\springframework\web\servlet\mvc\method\annotation\ExceptionHandlerExceptionResolver.class#initExceptionHandlerAdviceCache,如下:
java
private void initExceptionHandlerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// 这里的adviceBeans 会找到包含开发自己创建的全局异常处理器类
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");
}
}
}
D:\JavaKFHJ\repository\org\springframework\spring-web\6.1.6\spring-web-6.1.6.jar!\org\springframework\web\method\ControllerAdviceBean.class#findAnnotatedBeans会找到由@ControllerAdvice标注的类并返回,如下:
java
public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
ListableBeanFactory beanFactory = context;
if (context instanceof ConfigurableApplicationContext cac) {
// Use internal BeanFactory for potential downcast to ConfigurableBeanFactory above
// 从context中取出beanFactory
beanFactory = cac.getBeanFactory();
}
List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
// 取出所有bean的名字列表
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class)) {
if (!ScopedProxyUtils.isScopedTarget(name)) {
// 如果这个bean上有@ControllerAdvice的注解
ControllerAdvice controllerAdvice = beanFactory.findAnnotationOnBean(name, ControllerAdvice.class);
if (controllerAdvice != null) {
// Use the @ControllerAdvice annotation found by findAnnotationOnBean()
// in order to avoid a subsequent lookup of the same annotation.
adviceBeans.add(new ControllerAdviceBean(name, beanFactory, controllerAdvice));
}
}
}
OrderComparator.sort(adviceBeans);
return adviceBeans;
}

找到了开发自定义的全局异常处理器,有了这个类,开发写的由@ExceptionHandler注解的对于不同类型异常的处理方法也算已知了
