快捷搜索:  汽车  科技

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)实例化并注册一个ExceptionHandlerExceptionResolver 的实例但此时,过滤器已全部执行完。当所有Filter被执行完毕,Spring才会处理Servlet相关,而DispatcherServlet才是整个Servlet处理核心,它是前端控制器设计模式,提供 Spring Web MVC 的集中访问点并负责职责的分派。在这,Spring处理了请求和处理器的对应关系及统一异常处理。Filter内异常无法被统一处理,就是因为异常处理发生在 DispatcherServlet#doDispatch()

错误场景

验证请求的Token合法性的Filter。Token校验失败时,直接抛自定义异常,移交给Spring处理:

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(1)

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(2)

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(3)

测试HTTP请求:

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(4)

日志输出如下:说明IllegalRequestExceptionHandler未生效。

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(5)

why? 这就需要精通Spring异常处理流程了。

解析

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(6)

当所有Filter被执行完毕,Spring才会处理Servlet相关,而DispatcherServlet才是整个Servlet处理核心,它是前端控制器设计模式,提供 Spring Web MVC 的集中访问点并负责职责的分派。

在这,Spring处理了请求和处理器的对应关系及统一异常处理

Filter内异常无法被统一处理,就是因为异常处理发生在 DispatcherServlet#doDispatch()

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(7)

但此时,过滤器已全部执行完

Spring异常统一处理ControllerAdvice如何被Spring加载并对外暴露?WebMvcConfigurationSupport#handlerExceptionResolver()

实例化并注册一个ExceptionHandlerExceptionResolver 的实例

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(8)

最终按下图调用栈,Spring 实例化了ExceptionHandlerExceptionResolver类。

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(9)

ExceptionHandlerExceptionResolver实现了InitializingBean

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(10)

重写 afterPropertiesSet()

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(11)

initExceptionHandlerAdviceCache

完成所有 ControllerAdvice 中的ExceptionHandler 初始化:查找所有 @ControllerAdvice 注解的 Bean,把它们放入exceptionHandlerAdviceCache。 这里即指自定义的IllegalRequestExceptionHandler

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(12)

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(13)

所有被 @ControllerAdvice 注解的异常处理器,都会在 ExceptionHandlerExceptionResolver 实例化时自动扫描并装载在其exceptionHandlerAdviceCache。

initHandlerExceptionResolvers

当第一次请求发生时,DispatcherServlet#initHandlerExceptionResolvers() 将获取所有注册到 Spring 的 HandlerExceptionResolver 实例(ExceptionHandlerExceptionResolver正是),存到handlerExceptionResolvers

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(14)

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(15)

ControllerAdvice如何被Spring消费并处理异常?DispatcherServletdoDispatch()

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(16)

执行用户请求时,当查找、执行请求对应的 handler 过程中异常时:

  1. 会把异常值赋给 dispatchException
  2. 再移交 processDispatchResult()
processDispatchResult

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(17)

当Exception非空时,继续移交

processHandlerException

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(18)

从 HandlerExceptionResolvers 获取有效的异常解析器以解析异常。

这里的 handlerExceptionResolvers 一定包含声明的IllegalRequestExceptionHandler#IllegalRequestException 的异常处理器的 ExceptionHandlerExceptionResolver 包装类。

修正

为利用到 Spring MVC 的异常处理机制,改造Filter:

  • 手动捕获异常
  • 将异常通过 HandlerExceptionResolver 进行解析处理

据此,修改 PermissionFilter,注入 HandlerExceptionResolver:

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(19)

然后,在 doFilter 捕获异常并移交 HandlerExceptionResolver:

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(20)

现在再用错误 Token 请求,日志输出如下:

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(21)

响应体:

手撕阿里spring框架(阿里四面SpringException的原理你精通了吗)(22)

猜您喜欢: