Spring异常处理三种⽅式@ExceptionHandler
问题描述: 假如对异常不进⾏处理?
假如SpringMvc我们不对异常进⾏任何处理, 界⾯上显⽰的是这样的.
异常处理的⽅式有三种:
⼀. Controller层⾯上异常处理 @ExceptionHandler
说明:针对可能出问题的Controller,新增注解⽅法@ExceptionHandler.
spring framework怎么卸载@Controller
@RequestMapping("/testController")
public class TestController {
@RequestMapping("/demo1")
@ResponseBody
public Object demo1(){
int i = 1 / 0;
return new Date();
}
@ExceptionHandler({RuntimeException.class})
public ModelAndView fix(Exception ex){
System.out.println("do This");
return new ModelAndView("error",new ModelMap("ex",ex.getMessage()));
}
}
注意事项: 1. ⼀个Controller下多个@ExceptionHandler上的异常类型不能出现⼀样的,否则运⾏时抛异常.
Ambiguous @ExceptionHandler method mapped for;
2. @ExceptionHandler下⽅法返回值类型⽀持多种,常见的ModelAndView,@ResponseBody注解标注,ResponseEntity等类型都OK.
原理说明:
代码⽚段位于:org.springframework.web.servlet.DispatcherServlet#doDispatch
执⾏@RequestMapping⽅法抛出异常后,Spring框架 try-catch的⽅法捕获异常,  正常逻辑发不发⽣异常都会⾛processDispatchResult流程,区别在于异常的参数是否为null .
HandlerExecutionChain mappedHandler = null;
Exception dispatchException = null;
ModelAndView mv = null;
try{
mappedHandler=getHandler(request); //根据请求查handlerMapping到controller
HandlerAdapter ha = Handler());//到处理器适配器HandlerAdapter
if(!mappedHandler.applyPreHandle(request,response)){ //preHandle
return ;
}
mv=ha.handle(request,response); //调⽤处理器适配器执⾏@RequestMapping⽅法
mappedHandler.applyPostHandle(request,response,mv);  //postHandle
}catch(Exception ex){
dispatchException=ex;
}
processDispatchResult(request,response,mappedHandler,mv,dispatchException) //将异常信息传⼊了
代码⽚段位于:org.springframework.web.servlet.DispatcherServlet#processDispatchResult
如果@RequestMapping⽅法抛出异常,的postHandle⽅法不执⾏,进⼊ processDispatchResult,判断⼊参 dispatchException,不为null , 代表发⽣异常,调⽤processHandlerException处理,
代码⽚段位于:org.springframework.web.servlet.DispatcherServlet#processHandlerException
this当前对象指dispatchServlet,handlerExceptionResolvers可以看到有三个HandlerExceptionResolver, 这三个是<mvc:annotation-driven />帮我们注册的.  遍历有序集合handlerExceptionResolvers,调⽤接⼝的resolveException⽅法.
记录<mvc:annotation-driven/>注册的第⼀个 HandlerExceptionResolver : ExceptionHandlerExceptionResolver,  继承关系如下⾯所⽰.
代码⽚段位于:org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#resolveException
AbstractHandlerExceptionResolver 和 AbstractHandler Method ExceptionResolver名字看起来⾮常相似. 这⾥AbstractHandlerExceptionResolver 的shouldApplyTo都返回 true, logException⽤来记录⽇志、prepareResponse⽅法⽤来设置response的Cache-Control.    异常处理⽅法就位于doResolveException.
代码⽚段位于:org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver#shouldApplyTo
接⼝⽅法实现是AbstractHandlerExceptionResolver的resolveException,先判断 shouldApplyTo, AbstractHandlerExceptionResolver 和⼦类
AbstractHandler Method ExceptionResolver都实现了shouldApplyTo⽅法,⼦类的shouldApplyTo都调⽤⽗类AbstractHandlerExceptionResolver的shouldApplyTo.
查看⽗类AbstractHandlerExceptionResolver的shouldApplyTo⽅法.
代码⽚段位于:org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#shouldApplyTo
Spring初始化的时候并没有额外配置 , 所以mappedHandlers和mappedHandlerClasses都为null,  可以在这块扩展进⾏筛选,AbstractHandlerExceptionResolver提供了setMappedHandlerClasses 、setMappedHandlers⽤于扩展.
代码⽚段位于:org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver#doResolveException
代码⽚段位于:org.springframework.web.hod.annotation.ExceptionHandlerExceptionResolver#doResolveHandlerMethodException
似曾相识的ServletInvocableHandlerMethod,getExceptionHandlerMethod⽬的就是获取针对异常的处理⽅法,没到的话这⾥就直接返回了,到了执⾏异常处理⽅法;
之后同Spring请求⽅法执⾏⼀样的处理⽅式,设置argumentResolvers、returnValueHandlers,之后进⾏调⽤异常处理⽅法,
@ExceptionHandler的⽅法⼊参⽀持:Exception ;SessionAttribute 、 RequestAttribute注解; HttpServletRequest  、HttpServletResponse、HttpSession.
@ExceptionHandler⽅法返回值常见的可以是: ModelAndView 、@ResponseBody注解、ResponseEntity;
getExceptionHandlerMethod说明:获取对应的@ExceptionHandler⽅法,封装成ServletInvocableHandlerMethod返回.
代码⽚段位于:org.springframework.web.hod.annotation.ExceptionHandlerExceptionResolver#getExceptionHandlerMethod
exceptionHandlerCache是针对Controller层⾯的@ExceptionHandler的处理⽅式,⽽exceptionHandlerAdviceCache是针对@ControllerAdvice的处理⽅式. 这两个属性都位于ExceptionHandlerExceptionResolver中.
handlerType指代Controller的class属性,尝试从缓存A exceptionHandlerCache 中根据controller的class  查ExceptionHandlerMethodResolver;缓存A之前没存储过Controller 的class  ,所以新建⼀个ExceptionHandlerMethodResolver 加⼊缓存中.  ExceptionHandlerMethodResolver 的初始化⼯作⼀定做了某些⼯作!
resolveMethod⽅法:根据异常对象让  ExceptionHandlerMethodResolver 解析得到 method ,匹配到异常处理⽅法就直接封装成对象 ServletInvocableHandlerMethod ;就不会再去⾛@ControllerAdvice⾥的异常处理器了.  这⾥说明了,ExceptionHandlerMethodResolver 初始化的时候完成存储 @ExceptionHandler.
查看ExceptionHandlerMethodResolver 初始化⼯作内容:
代码⽚段位于:org.hod.annotation.ExceptionHandlerMethodResolver#ExceptionHandlerMethodResolver
handlerType为传⼊的Controller的class属性,通过EXCEPTION_HANDLER_METHODS选出 class 中标注@ExceptionHandler的⽅法,解析@Exception注解的value值(class类型的数组),并加⼊到当前ExceptionHandlerMethodResolver的mappedMethods集合中,key为异常类型,value为 method.
如果@ExceptionHandler的 value属性为空,就会将⽅法⼊参中的Throwable的⼦类作为异常类型.  @ExceptionHandler的value属性和⽅法⼊参不能同时都为空,否则会抛出异常.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。