标签:log message des png except cts 技巧 targe 返回值
SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧
本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC如何完成异常解析、捕捉异常,并自定义异常和异常解析器
进入DispatcherServlet的processDispatchResult方法
1024行判断异常是否是ModelAndViewDefiningException类型,如果是,直接返回ModelAndView
不是ModelAndViewDefiningException类型,则获取HandlerMethod,调用processHandlerExeception方法
点进去1030行的processHandlerException方法,该方法根据HandlerExecutionResolvers来解析异常并选择ModelAndView
1217行遍历HandlerExecutionResolvers,我们讲过,在<mvc:annotation-driven/>帮我们注册了默认的异常解析器
请看AnnotationDrivenBeanDefinitionParser(解析annotation-driven的类)
1218行调用HandlerExceptionResolver的resolveException方法,该方法被子类AbstractHandlerExceptionResolver实现
1225行给request设置异常信息
现在进入HandlerExceptionResolver接口resolveException方法的实现处——AbstractHandlerExceptionResolver的resolveException方法
131行判断该异常解析器是否可以被应用到Handler
135行为异常情况准备response,即给response添加头部
136行调用抽象方法doResolveException,由子类实现
进入AbstractHandlerMethodExceptionResolver的doResolveException方法
59行调用抽象方法,被子类ExceptionHandlerExceptionResolver实现
打开ExceptionHandlerExceptionResolver的doResolveHandlerMethodException方法
362行获取有异常的Controller方法
367~368行为ServletInvocableHandlerMethod设置HandlerMethodArgumentResolverComposite和HandlerMethodReturnValueComposite,用来解析参数和处理返回值
380行调用invokeAndHandle方法处理返回值,暴露cause
384行无cause
@ResponseStatus会被ResponseStatusExceptionResolver解析
@ResponseStatus(code=HttpStatus.UNAUTHORIZED,reason="用户未授权") public class UnauthorizedException extends RuntimeException { }
测试方法
@RequestMapping("/unauth") public Map unauth() { throw new UnauthorizedException(); }
浏览器输入http://localhost:8080/springmvcdemo/error/unauth
测试方法
@RequestMapping("/noSuchMethod") public Map noHandleMethod() throws NoSuchMethodException { throw new NoSuchMethodException(); }
没有@ExceptionHandler和@ResponseStatus注解则会被DefaultHandlerExceptionResolver解析
浏览器输入http://localhost:8080/springmvcdemo/error/noSuchMethod
测试方法
@ExceptionHandler会被ExceptionHandlerExceptionResolver解析
@RequestMapping("/exception") @ResponseBody public Map exception() throws ClassNotFoundException { throw new ClassNotFoundException("class not found"); } @RequestMapping("/nullpointer") @ResponseBody public Map nullpointer() { Map resultMap = new HashMap(); String str = null; str.length(); resultMap.put("strNullError",str); return resultMap; } @ExceptionHandler(RuntimeException.class) @ResponseBody public Map error(RuntimeException error, HttpServletRequest request) { Map resultMap = new HashMap(); resultMap.put("param", "Runtime error"); return resultMap; } @ExceptionHandler() @ResponseBody public Map error(Exception error, HttpServletRequest request, HttpServletResponse response) { Map resultMap = new HashMap(); resultMap.put("param", "Exception error"); return resultMap; }
浏览器输入http://localhost:8080/springmvcdemo/error/classNotFound
浏览器输入http://localhost:8080/springmvcdemo/error/nullpointer
根据异常类继承关系,ClassNotFoundException离Exception更近,所以被@ExceptionHandler()的error方法解析,注解无参相当于Exception.class。
同理,NullPointerException方法离NullPointerException“最近”,把@ExceptionHandler(NullPointerException.class)的error方法注释掉,浏览器输入http://localhost:8080/springmvcdemo/error/nullpointer,会发现
浏览器返回RuntimeException,印证了我们的说法
/** * @Author: 谷天乐 * @Date: 2019/1/21 10:48 * @Description: ExceptionHandlerMethodResolver内部找不到Controller的@ExceptionHandler注解的话, * 会找@ControllerAdvice中的@ExceptionHandler注解方法 */ @ControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(Throwable.class) @ResponseBody public Map<String, Object> ajaxError(Throwable error, HttpServletRequest request, HttpServletResponse response) { Map<String, Object> map = new HashMap<String, Object>(); map.put("error", error.getMessage()); map.put("result", "error"); return map; } }
浏览器输入http://localhost:8080/springmvcdemo/error/unauth
优先级关系:@ExceptionHandler>@ControllerAdvice中的@ExceptionHandler>@ResponseStatus
要把TestErrorController中@ExceptionHandler的方法注释掉才会有效果
HandlerExceptionResolver作为异常解析器的接口,核心方法是resolveException
AbstractHandlerExceptionResolver实现HandlerException,resolveException方法内部调用抽象方法doResolveException,该方法被子类实现;shouldApplyTo方法检查该异常解析器是否可以被应用到Handler
AbstractHandlerMethodExceptionResolver的doResolveException内部调用抽象方法doResolveHandlerMethodException,由子类实现,返回ModelAndView,可以在视图模型里自定义错误页面;shouldApplyTo调用父类方法
ExceptionHandlerExceptionResovler的doResolveHandlerMethodException处理异常,返回ModelAndView
DefaultHandlerExceptionResolver的doResolveException处理默认异常
ResponseStatusExceptionResolver的doResolveException方法处理@ResponseStatus修饰的异常
DispatcherServler的processHandlerException方法根据注册的HandlerExceptionResolvers选择一个ModelAndView
DispatcherServlet的doDispatch方法调用processDispatchResult,该方法处理Handler的选择和调用的结果,processDispatchResult方法调用processHandlerException
https://docs.spring.io/spring/docs/current/javadoc-api/
https://github.com/spring-projects/spring-framework
文中难免有不足,欢迎指正
标签:log message des png except cts 技巧 targe 返回值
原文地址:https://www.cnblogs.com/Java-Starter/p/10356055.html