SpringBoot自定义异常源码分析

SpringBoot自定义异常源码分析

 

在类上加ControllerAdvice注解,在方法上加ExceptionHandler注解,就可以在方法里处理相应的异常。

1.自定义异常处理类AdditionalExceptionHandler

挂@RestControllerAdvice注解:

------------------

2.自定义异常处理类GlobalExceptionHandler

=======================

初始调用链

main函数出发refreshContext

调用refresh

 进入context

 

AbstractApplicationContext调用beanFactory

getBean

 

org.springframework.beans.factory.support包下的一系列factory调用:

 SimpleInstantiationStrategy类的

instantiate方法触发对WebMvcAutoConfiguration的反射

WebMvcAutoConfiguration类

configureHandlerExceptionResolvers方法

调用addDefaultHandlerExceptionResolvers(exceptionResolvers);

addDefaultHandlerExceptionResolvers类

调用exceptionHandlerResolver.afterPropertiesSet();

ExceptionHandlerExceptionResolver类的

afterPropertiesSet()调用initExceptionHandlerAdviceCache()

-----------------

异常核心处理类ExceptionHandlerExceptionResolver类

这个类扫描了所有标注有ExceptionHandler注解的方法,并将他们存入exceptionHandlerAdviceCache中

------------

initExceptionHandlerAdviceCache方法

先找到异常注解的bean

List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

对其循环

for (ControllerAdviceBean adviceBean : adviceBeans)

判断是否有异常映射

if (resolver.hasExceptionMappings())

放到异常句柄缓存

this.exceptionHandlerAdviceCache.put(adviceBean, resolver);

-----------------------

ControllerAdviceBean类的findAnnotatedBeans方法找到@ControllerAdvice注解的bean

findAnnotatedBeans流式编程findAnnotationOnBean判断是否是ControllerAdvice.class

 

------------------------

ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);

调用ExceptionHandlerMethodResolver,这里就是

遍历自定义异常类AdditionalExceptionHandler (参考1)的方法method

-------------------

selectMethods判断是否有ExceptionHandler注解

------

这个MethodIntrospector类的selectMethods很复杂

Select methods on the given target type based on the lookup of associated metadata.

查找给定类型的方法

>>>

selectMethods调用ReflectionUtils.doWithMethods

<<<回到selectMethods判断是否桥接方法

Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
   methodMap.put(specificMethod, result);
}

什么时候会生成桥接方法
那什么时候编译器会生成桥接方法呢?可以查看JLS中的描述http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.4.5。

就是说一个子类在继承(或实现)一个父类(或接口)的泛型方法时,在子类中明确指定了泛型类型,那么在编译时编译器会自动生成桥接方法

------------------------

最关键就是EXCEPTION_HANDLER_METHODS

EXCEPTION_HANDLER_METHODS判断是否有ExceptionHandler注解,

回过来看AdditionalExceptionHandler自定义异常定义了有ExceptionHandler注解的方法

--------------------

ExceptionHandlerMethodResolver的addExceptionMapping的put操作:

=====================

hasExceptionMappings判断方法:

mappedMethods定义:

 

看看mappedMethods的调用,直接点或者Ctrl+Alt+H都可以看到变量调用点:

--------------

 

this.exceptionHandlerAdviceCache.put(adviceBean, resolver);

 

如果觉得前面的分析比较繁琐,这个写的比较简洁可以参考下

https://juejin.im/post/5cad5143f265da03b20413a6

==========================

【异常的触发】

前面讲了异常的注解初始化的时候扫描,现在我们故意触发一段异常。

json数据格式异常触发fastjson异常。这个异常被

DispatcherServlet的doDispatch捕获

processDispatchResult结果处理

判断是否是异常,是异常进行异常处理processHandlerException

遍历handlerExceptionResolvers。

 

进入

protected final ModelAndView doResolveException

再进入doResolveHandlerMethodException

getExceptionHandlerMethod

异常判断

异常类型判断

resolveMethod调用resolveMethodByThrowable

异常命中以后

ServletInvocableHandlerMethod(advice.resolveBean(), method);

进入HandlerMethod

回到

doResolveHandlerMethodException

进入

exceptionHandlerMethod.invokeAndHandle

开始反射执行自定义的全局异常

bean就是之前定义的GlobalExceptionHandler

进入自定义的异常处理方法

封装返回对象

一直返回多次回到

invokeAndHandle

返回ModelAndView()

返回

回到processRequest

经过一系列的FilterChain

回到tomcat的代码做输出了

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读