说在前面
前期回顾
sharding-jdbc源码解析 更新完毕
spring源码解析 更新完毕
spring-mvc源码解析 更新完毕
spring-tx源码解析 更新完毕
spring-boot源码解析 更新完毕
rocketmq源码解析 更新完毕
dubbbo源码解析 更新完毕
netty源码解析 更新完毕
spring源码架构更新完毕
springmvc源码架构更新中
springboot源码架构计划中
github https://github.com/tianheframe
sharding-jdbc源码解析 更新完毕
rocketmq源码解析 更新完毕
seata 源码解析 更新完毕
dubbo 源码解析 更新完毕
netty 源码解析 更新完毕
源码解析
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver org.springframe .web.servlet的实现。HandlerExceptionResolver接口,它通过ExceptionHandler注释处理异常。此异常解析器在org.springframework.web.servlet.DispatcherServlet中默认启用。
private final Map, Map, Method>> exceptionHandlerCache = new ConcurrentHashMap, Map, Method>>(64);
exceptionHandlerCache
private WebArgumentResolver[] customArgumentResolvers;
customArgumentResolvers
private HttpMessageConverter>[] messageConverters = new HttpMessageConverter>[] {new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter(), new SourceHttpMessageConverter(), new org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter()};
messageConverters
public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { this.customArgumentResolvers = new WebArgumentResolver[]{argumentResolver}; }
设置用于特殊方法参数类型的自定义参数解析器。这样的自定义ArgumentResolver将首先起作用,有机会在标准的参数处理起作用之前解析一个参数值。
public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) { this.customArgumentResolvers = argumentResolvers; }
设置一个或多个用于特殊方法参数类型的自定义参数解析器。任何这样的自定义ArgumentResolver都将首先起作用,有机会在标准的参数处理起作用之前解析一个参数值。
public void setMessageConverters(HttpMessageConverter>[] messageConverters) { this.messageConverters = messageConverters; }
设置要使用的消息正文转换器。这些转换器用于将请求和响应转换为HTTP请求和响应。
@Override protected ModelAndView doResolveException( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if (handler != null) {// 找到异常handler的方法 Method handlerMethod = findBestExceptionHandlerMethod(handler, ex); if (handlerMethod != null) { ServletWebRequest webRequest = new ServletWebRequest(request, response); try {// 解析handler参数 Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, ex); if (logger.isDebugEnabled()) { logger.debug("Invoking request handler method: " + handlerMethod); }// 执行方法 Object retVal = doInvokeMethod(handlerMethod, handler, args);// 获得modelAndView return getModelAndView(handlerMethod, retVal, webRequest); } catch (Exception invocationEx) { logger.error("Invoking request method resulted in exception : " + handlerMethod, invocationEx); } } } return null; }
解析异常返回modelAndView,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver#getModelAndView 获得modelAndView
private ModelAndView getModelAndView(Method handlerMethod, Object returnValue, ServletWebRequest webRequest) throws Exception { ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(handlerMethod, ResponseStatus.class); if (responseStatus != null) { HttpStatus statusCode = responseStatus.code(); String reason = responseStatus.reason(); if (!StringUtils.hasText(reason)) { webRequest.getResponse().setStatus(statusCode.value()); } else { webRequest.getResponse().sendError(statusCode.value(), reason); } } if (returnValue != null && AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {// 执行@ResponseBody return handleResponseBody(returnValue, webRequest); } if (returnValue instanceof ModelAndView) { return (ModelAndView) returnValue; } else if (returnValue instanceof Model) { return new ModelAndView().addAllObjects(((Model) returnValue).asMap()); } else if (returnValue instanceof Map) { return new ModelAndView().addAllObjects((Map<String, Object>) returnValue); } else if (returnValue instanceof View) { return new ModelAndView((View) returnValue); } else if (returnValue instanceof String) { return new ModelAndView((String) returnValue); } else if (returnValue == null) { return new ModelAndView(); } else { throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); } }
protected Listextends Throwable>> getHandledExceptions(Method method) { Listextends Throwable>> result = ExceptionHandler exceptionHandler = AnnotationUtils.findAnnotation(method, ExceptionHandler.class); if (exceptionHandler != null) { if (!ObjectUtils.isEmpty(exceptionHandler.value())) { result.addAll(Arrays.asList(exceptionHandler.value())); } else { for (Class> param : method.getParameterTypes()) { if (Throwable.class.isAssignableFrom(param)) { result.add((Class extends Throwable>) param); } } } } return result; }
返回由给定方法处理的所有异常类。默认实现在注释中查找异常,或者(如果注释元素为空)方法参数中列出的任何异常(如果方法使用@ExceptionHandler进行注释)。
protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest, Exception thrownException) throws Exception { // Invoke custom argument resolvers if present... if (this.customArgumentResolvers != null) { for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { Object value = argumentResolver.resolveArgument(methodParameter, webRequest); if (value != WebArgumentResolver.UNRESOLVED) { return value; } } } // Resolution of standard parameter types... Class> paramType = methodParameter.getParameterType(); Object value = resolveStandardArgument(paramType, webRequest, thrownException); if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { throw new IllegalStateException( "Standard argument type [" + paramType.getName() + "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + "]. Consider declaring the argument type in a less specific fashion."); } return value; }
解析常用方法参数。首先委托给注册的argumentResolvers,然后检查resolveStandardArgument。org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver#resolveStandardArgument 解析标准方法参数。默认实现处理NativeWebRequest、ServletRequest、ServletResponse、HttpSession、主体、语言环境、请求InputStream、请求阅读器、响应OutputStream、响应写入器和给定的thrownException。
protected Object resolveStandardArgument(Class> parameterType, NativeWebRequest webRequest, Exception thrownException) throws Exception { if (parameterType.isInstance(thrownException)) { return thrownException; } else if (WebRequest.class.isAssignableFrom(parameterType)) { return webRequest; } HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); if (ServletRequest.class.isAssignableFrom(parameterType)) { return request; } else if (ServletResponse.class.isAssignableFrom(parameterType)) { return response; } else if (HttpSession.class.isAssignableFrom(parameterType)) { return request.getSession(); } else if (Principal.class.isAssignableFrom(parameterType)) { return request.getUserPrincipal(); } else if (Locale.class == parameterType) { return RequestContextUtils.getLocale(request); } else if (InputStream.class.isAssignableFrom(parameterType)) { return request.getInputStream(); } else if (Reader.class.isAssignableFrom(parameterType)) { return request.getReader(); } else if (OutputStream.class.isAssignableFrom(parameterType)) { return response.getOutputStream(); } else if (Writer.class.isAssignableFrom(parameterType)) { return response.getWriter(); } else { return WebArgumentResolver.UNRESOLVED; } }
说在最后
本次解析仅代表个人观点,仅供参考。
![1c2e878758bd076c580969ee884b6fcf.gif](https://img-blog.csdnimg.cn/img_convert/1c2e878758bd076c580969ee884b6fcf.gif)
扫码进入技术微信群
![34996293b72c228a056d2065f067925b.png](https://img-blog.csdnimg.cn/img_convert/34996293b72c228a056d2065f067925b.png)
![9931eee1a7192a96a0f193ce836c8585.png](https://img-blog.csdnimg.cn/img_convert/9931eee1a7192a96a0f193ce836c8585.png)
![23f4edcad7cb50a301faa0d7fdcfd2cc.png](https://img-blog.csdnimg.cn/img_convert/23f4edcad7cb50a301faa0d7fdcfd2cc.png)
qq技术群