07springmvc全局异常处理源码分析
2022-12-01 11:44:07 6 举报
1、简单介绍spring全局异常的案例和使用2、重点介绍ExceptionHandlerExceptionResolver的执行流程3、重点介绍ExceptionHandlerExceptionResolver初始化流程
作者其他创作
大纲/内容
doDispatch()
判断当前类是否被ControllerAdviceBean修饰,判断依据为 ControllerAdviceBean上设置的注解@ControllerAdvice内的参数
如果不做一些自定义的操作,以及配置,那么controller内部的异常,一般是不会被springmvc解决的,如果解决不了,就向上抛,一直给到servlet容器--tomcat。
AbstractHandlerMethodExceptionResolver#shouldApplyTo
returnValueHandlers.handleReturnValue()--???????
异常处理流程---源码分析针对最复杂的ExceptionHandlerExceptionResolve做的分析
这3个ExceptionResolver最终被会加入到DispatcherServlet中的handlerExceptionResolvers集合中。其中ExceptionHandlerExceptionResolver优先级最高,ResponseStatusExceptionResolver第二,DefaultHandlerExceptionResolver第三。
this.resolveMethodByThrowable(exception);
(Method)this.mappedMethods.get(matches.get(0));
总之就是得到当前类里面的上面有@ExceptionHandler注解的方法
Method method = resolver.resolveMethod(exception);
通过反射调用自定义异常类返回的信息
!true=false
遍历this.exceptionHandlerAdviceCache这里面存储的就是注册到spring容器中的全局自定义异常类
ExceptionHandlerExceptionResolver#getExceptionHandlerMethod
ExceptionHandlerExceptionResolver()
判断是否被ResponseBodyAdvice注解。
缓存里面找
如果一个类中,两个方法的异常一样,则会报错
下面主要内容概括:1、简单介绍spring全局异常的案例和使用2、重点介绍ExceptionHandlerExceptionResolver的执行流程3、重点介绍ExceptionHandlerExceptionResolver初始化流程先看一些博客了解后,再看这个可能会容易理解,个人笔记,比较随意。。。
判断容器是否为null
因为这个方法实现了InitializingBean接口
其他三个解析器,一般不会有自定义的初始化操作,里面默认实现了很多判断
这是springmvc默认的异常处理方式,会交给DefaultHandlerExceptionResolver处理
return new ModelAndView();
调用ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
ServletInvocableHandlerMethod#invokeAndHandle
this指的是当前的异常解析器比如ExceptionHandlerExceptionResolver
key 为类--方法维度hashmap 类型,所以同一个key会被后面的覆盖
前面做的就是spring容器的初始化
afterPropertiesSet()
这里关注的是这个方法,所以先进入这个类的构造方法
为什么ExceptionHandlerExceptionResolver优先级最高,因为order属性值最低,
getMappedMethod(exceptionType);
拿到当前的自定义异常类,拿到当前的异常信息为参数,然后得到里面的处理方法
结束
AbstractHandlerMethodExceptionResolver#doResolveException
if (advice.isApplicableToBeanType(handlerType)) {
null
对返回的modelAndVie做一个校验 return this.view == null && CollectionUtils.isEmpty(this.model);
内部
Dispatcherservlet#processDispatchResult()
matches.sort(new ExceptionDepthComparator(exceptionType));
return this.doInvoke(args);
添加一些缓存头信息
Method method = (Method)this.exceptionLookupCache.get(exceptionType);
自定义标签解析的部分流程
ture
到这里应该是,在当前的cotroller内部的自定义的@ExceptionHandler方法没找到,接着找全局的@RestControllerAdvice类
该方法会遍历所有的handlerExceptionResolvers,判断能否处理该异常。调用各自的resolveException 方法(一般抛出的异常都需要通过这一步,要么能被处理;要么处理不了,向上抛)。
内
return null
每个方法上面可能有多个异常,依次获取并遍历,方法参数可以定义异常
做一个和当前发生的异常和异常深度排序
如果一个普通的controller里面定义了@ExceptionHandler方法,在这一步是不会被解析的,所以在异常处理的时候,是先解析当前controller里面有没有定义异常解析的方法,然后再走全局的自定义异常解析器
设置一些属性
遍历当前匹配到的自定义的类里面的每个方法,如果匹配上了,就放到一个list里面
指定了modelAndView,所以直接拿到该mv,执行就行。
返回第一个方法
注:public class Exception extends Throwable
1、自定义异常一般主要是实现HandlerExceptionResolver接口或继承AbstractHandlerExceptionResolver2、使用注解@ExceptionHandler,@ControllerAdvice
ExceptionHandlerExceptionResolver#doResolveHandlerMethodException
得到被ControllerAdvice、RestControllerAdvice注解的类
new ExceptionHandlerMethodResolver(beanType);
进入抽象父类方法AbstractHandlerExceptionResolver#resolveException
this.resolveMethodByExceptionType(exception.getClass());
parseBeanDefinitions()
@RequestMapping(\"/err1\") public void handlerExceptionResolver(@RequestParam(\"name\") String name) { } 请求的时候,不传name字段的错误提示
如果没在上一个异常解析器中得到结果,返回null
可能会返回多个,然后做个排序
InvocableHandlerMethod类
if (exception instanceof ModelAndViewDefiningException) {//若抛出的异常是人为的指定mv的,则直接执行
如果返回不为空,跳出循环,不再遍历其他的异常解析器
三个默认的异常解析器的初始化位置是:1、通过<mvc:annotation注解初始化2、springmvc默认加载右边这个配置文件下的信息都是在spring容器初始化的时候加载的,所以一些spring的流水线上走一遍,改执行的都会执行,初始化的各种回调。这里不细说了。
依次遍历this.handlerExceptionResolvers
总之解析出所有的beanNames
遍历每个自定义类
初始化流程分析
1、通过读取默认配置文件得到2、通过监听器回调onfresh接口的得到3、配置文件增加<mvc注解,扩展自定义标签来解析,然后注册到容器中
this.mappedHandlersthis.mappedHandlerClasses
迭代下一个异常解析器
this.setResponseStatus(webRequest);
AbstractHandlerExceptionResolver#shouldApplyTo
放到缓存
主要关注ExceptionHandlerExceptionResolve初始化流程分析
这四个默认的异常解析器。其中只有ExceptionHandlerExceptionResolver实现了InitializingBean接口,所以在初始化完成后,spring会在生命周期中回调afterPropertiesSet()方法,完成一些后续如果必要的初始化操作
ReflectionUtils.makeAccessible(this.getBridgedMethod());设置权限啥的
这样bean的生命周期就交给spring管理了
可能返回多个方法,依次迭代
mavContainer.setRequestHandled(false);
上面方法,返回一个迭代器
return null
解析完成
EXCEPTION_HANDLER_METHODS参数实际是
可能return null
initExceptionHandlerAdviceCache();
做一些判断或强转成HandlerMethod
解析成功
0 条评论
下一页