spring异常处理
在项目中采用spring的异常处理机制:
示例一、在Controller中加@ExceptionHandler注解定义异常拦截的方法,在方法中定义返回的页面:
@Controller
public class ExceptionTestController {@ExceptionHandlerpublic String handleException(Exception e) {return "error";}@RequestMapping("/error")public String error(Model model) {throw new RuntimeException();}
}
error.jsp
ok
===============error============
示例二、将异常处理做成一个公共的:
@ControllerAdvice
public class ViewExceptionHandler {@ExceptionHandler(value = Exception.class)public String handleException(Exception e) {return "error";}
}
效果:

两者区别:示例一只能捕获所属Controller中的方法抛出的异常,不能捕获其他Controller中的,示例二可以捕获所有Controller抛出的异常。
下面看源码分析:

由handlerAdapter进行反射调用后,调到controller中的具体方法,抛出的异常最终被捕获,将异常赋值给dispatchException,并调用processDispatchResult方法:

这里获取到handlerMethod

这里异常解析器是一个混合体,里面有三个异常解析器,这三个异常解析器是什么时候初始化的?
在DispatcherServlet的父类FrameworkServlet中定义了一个内部类,监听spring容器启动后的事件发布:

会调到DispatcherServlet中的onRefresh方法:

在这个方法中会拿到spring容器中所有实现了HandlerExceptionResolver接口的实例:

那spring容器中的实例又是怎么来的呢?就是在开启mvc功能的时候:



如果没有自定义异常解析器,这里会添加默认的,看到的那三个异常解析器就是通过addDefaultHandlerExceptionResolvers方法添加的。这里不再赘述了,有兴趣的可以看一下这部分的源码。
言归正传,看这个混合体的resolveException方法:

最终会调到ExceptionHandlerExceptionResolver中的doResolveHandlerMethodException

看上图中的getExceptionHandlerMethod方法:



以上两个截图的意思是寻找controller中的带@ExceptionHandler注解的方法,也就是对应我们示例一中的情况(异常拦截方法和注解要求在controller里面),并获取@ExceptionHandler注解的值,也就是异常类型(如果没定义,就是java.lang.Exception),并建立异常类型和异常处理方法的映射。
建立好映射关系以后,会根据异常类型找到对应的处理方法,并根据controller和异常处理方法作为参数创建ServletInvocableHandlerMethod实例。

由构建的ServletInvocableHandlerMethod进行方法调用,参数解析后,最终会通过反射调到我们定义的异常处理方法:


接下来的逻辑和其他普通的方法处理一样,不再赘述。
也可以像示例二中的方式,我们单独的写一个全局的异常处理类,加上@ControllerAdvice注解

我们可以定义很多个方法,每个方法拦截的异常类型不一样,比如IOException、空指针异常等等。下面看示例二的源码:
和示例一的逻辑差不多,注释掉controller中的@ExceptionHandler方法之后,根据异常获取controller中对应的异常处理方法为空,就会往下走:

在exceptionHandlerAdviceCache当中找到一个我们定义的全局异常拦截类:

接下来的处理和示例一的就相同了,也是拿我们定义的异常处理类和方法构造ServletInvocableHandlerMethod,然后进行反射调用。
那么exceptionHandlerAdviceCache中是什么时候初始化的?
上面提到,在没有定义异常解析器的时候,spring会添加默认的异常解析器,看代码:

在这里会调用afterPropertiesSet()方法:



以上代码是拿到spring容器中所有的Object实例,查找有ControllerAdvice注解的bean。接下来拿到ControllerAdvice注解的bean的list集合后进行排序,然后遍历,如图:

new ExceptionHandlerMethodResolver(adviceBean.getBeanType())和上面讲过的一样,在构造方法中找全局异常拦截类中带@ExceptionHandler的方法,然后解析,然后建立异常类型和异常处理方法的映射关系。
然后将全局异常处理类和异常解析器放入exceptionHandlerAdviceCache。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
