首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SpringMVC的统一异常,你遇到坑了吗?

老顾导读

1、前言

2、ControllerAdvice使用

3、源码分析

4、initHandlerAdapters

5、initHandlerExceptionResolvers

6、碰到的坑

6、总结

一、前言

小伙伴们一看到SpringMVC的异常,就感觉很简单啊,不就是加个ControllerAdvice和ExceptionHandler了吗?我们先来看看ControllerAdvice怎么使用?

二、ControllerAdvice使用

现在我们的项目一般都是前后端分离了,所以一般我们会使用@RestControllerAdvice,

@RestControllerAdvice其实是@ControllerAdvice和@ResponseBody结合体。

我们来看看怎么使用

我们在类上加上@RestControllerAdvice,在方法上加@ExceptionHandler,这样就达到了捕获异常的作用。

@ControllerAdvice是在类上声明的注解,其用法主要有三点:

1、@ExceptionHandler注解标注的方法:用于捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的;

2、@InitBinder注解标注的方法:用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;

3、@ModelAttribute注解标注的方法:表示此方法会在执行目标Controller方法之前执行 。

此篇文章只介绍Exceptionhandler异常

注:@ControllerAdvice来声明一些全局性的东西,经常会和ExceptionHandler结合使用,但不仅仅如此;它还可以和InitBinder和ModelAttribute使用,可以其他全局配置的效果。

上面的代码我们ExceptionHandler处理了所有的Exception异常,当然我们还可以要求ExceptionHandler处理指定的异常,这样会更灵活。如:

@ExceptionHandler标注的多个方法分别表示只处理特定的异常。

需要注意的是当Controller抛出的某个异常多个@ExceptionHandler标注的方法都适用时,Spring会选择最具体的异常处理方法来处理也就是说@ExceptionHandler(Exception.class)这里标注的方法优先级最低,只有当其它方法都不适用时,才会来到这里处理。

三、源码分析

我们知道SpringMVC的入口是DispatcherServlet,我们先来看看DispatcherServlet

关于ControllerAdvice我们只需要关注initHandlerAdapters和initHandlerExceptionResolvers两个方法。

四、initHandlerAdapters

此方法会取得所有实现了HandlerAdapter接口的bean并保存起来,其中就有一个类型为RequestMappingHandlerAdapter的bean,这个bean就是@RequestMapping注解能起作用的关键,这个bean在应用启动过程中会获取所有被@ControllerAdvice注解标注的bean对象做进一步处理,关键代码在这里:

RequestMappingHandlerAdapter实现了InitializingBean,即在bean初始化完成后,执行afterPropertiesSet方法

以上处理之后,@ModelAttribute和@InitBinder就能起作用了。

五、initHandlerExceptionResolvers

此方法会取得所有实现了HandlerExceptionResolver接口的bean并保存起来,其中就有一个类型为ExceptionHandlerExceptionResolver的bean,这个bean在应用启动过程中会获取所有被@ControllerAdvice注解标注的bean对象做进一步处理,关键代码在这里

当Controller抛出异常时,DispatcherServlet通过ExceptionHandlerExceptionResolver来解析异常,而ExceptionHandlerExceptionResolver又通过ExceptionHandlerMethodResolver来解析异常ExceptionHandlerMethodResolver 最终解析异常找到适用的@ExceptionHandler标注的方法是这里:

至此关于ControllerAdvice就分析到这里。

六、碰到的坑

在使用过程中,我们发现并不是所有的异常都会走到我们定义的ControllerAdvice的ExceptionHandler注解的方法中。

在之前介绍filter和Interceptor文章中,我们了解到在java web中,原生listener,filter, servlet执行顺序为:

Listener------>Filter----->Servlet

而在SpringMVC中,实质就是一个DispatchServlet。

而在Servlet中,则是调用了HandlerInterceptor的各个方法,和最后ExceptionHandler处理

所以, 调用顺序会变成:

Listener------>Filter----->DispatchServlet ---->HandlerInterceptor.preHandle---->handle---->HandlerInterceptor. postHandle------>ExceptionHandler

我们发现filter在执行到ExceptionHandler前面,ExceptionHandler根本没法处理filter中产生的异常。那我们怎么才能获取到处理filter的异常呢?

处理的方案也有很多,老顾会在下一篇文章中介绍,小伙伴想要尽快知道,可在评论区留言

七、总结

今天老顾介绍SpringMVC的异常方案,以及源码分析,并留下了一个坑,希望能够帮助到小伙伴们。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OwtohITj5Hds_CGKaTq4EpHA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券