移動網(wǎng)站是什么意思百度廣告聯(lián)盟一個(gè)月能賺多少
問題:異常處理器在SpringMVC中是如何進(jìn)行初始化以及使用的?
Spring MVC提供處理異常的方式主要分為兩種:
1、實(shí)現(xiàn)HandlerExceptionResolver方式(HandlerExceptionResolver是一個(gè)接口,在SpringMVC有一些默認(rèn)的實(shí)現(xiàn)也可以自定義異常處理器)
2、@ExceptionHandler注解方式。注解方式也有兩種用法:
(1)使用在Controller內(nèi)部
(2)配置@ControllerAdvice一起使用實(shí)現(xiàn)全局處理
下面的HandlerExceptionResolver接口的類的繼承關(guān)系。
補(bǔ)充說明:注解@EnableWebMvc和<mvc:annotation-driven />
這個(gè)注解得作用就是相當(dāng)于再配置文件中加上<mvc:annotation-driven /> 本質(zhì)都是會默認(rèn)得注入一些SpringMVC得核心組件,比如RequestMappingHandlerMapping與RequestMappingHandlerAdapter等,而@EnableWebMvc注解 也是一樣得作用默認(rèn)得會加載一些組件。@EnableWebMvc通常是加載配置類上使用的,在初始化父容器的時(shí)候會進(jìn)行注解的解析然后裝載默認(rèn)組件。
不過SpringMVC中如果配置了 mvc:annotation-driven/ 或者使用了@EnableWebMvc就會引入的 HandlerExceptionResolverComposite,這個(gè)是包含ExceptionHandlerExceptionResolver、DefaultHandlerExceptionResolver、ResponseStatusExceptionResolver3個(gè)處理器的是一個(gè)組合模式,下面會涉及到這個(gè)
一、啟動源碼分析
0、DispatcherServlet#initStrategies()
回歸到DispatcherServlet在執(zhí)行初始化策略中,跳過其他看initHandlerExceptionResolvers(context)
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}
1 initHandlerExceptionResolvers()
找到類是HandlerExceptionResolver的Bean,加入到handlerExceptionResolvers,如果沒有的話,就用默認(rèn)的。這里的默認(rèn)是會取讀取DispatcherServlet.properties
private void initHandlerExceptionResolvers(ApplicationContext context) {this.handlerExceptionResolvers = null;if (this.detectAllHandlerExceptionResolvers) {// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());// We keep HandlerExceptionResolvers in sorted order.AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);}}else {try {HandlerExceptionResolver her =context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);this.handlerExceptionResolvers = Collections.singletonList(her);}catch (NoSuchBeanDefinitionException ex) {// Ignore, no HandlerExceptionResolver is fine too.}}// Ensure we have at least some HandlerExceptionResolvers, by registering// default HandlerExceptionResolvers if no other resolvers are found.if (this.handlerExceptionResolvers == null) {this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}
1.1 配置文件:DispatcherServlet.properties
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
1.2 getDefaultStrategies()
如果容器中獲取不到 ,就是在使用了@EnableWebMvc和<mvc:annotation-driven />后加載的默認(rèn)的組件還是獲取不到的話,就會從DispatcherServlet.properties中加載默認(rèn)的異常處理器。
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {String key = strategyInterface.getName();String value = defaultStrategies.getProperty(key);if (value != null) {String[] classNames = StringUtils.commaDelimitedListToStringArray(value);List<T> strategies = new ArrayList<>(classNames.length);for (String className : classNames) {try {Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());Object strategy = createDefaultStrategy(context, clazz);strategies.add((T) strategy);}catch (ClassNotFoundException ex) {throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]", ex);}catch (LinkageError err) {throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" +className + "] for interface [" + key + "]", err);}}return strategies;}else {return new LinkedList<>();}}
1.2.1 createDefaultStrategy()
SpringMVC中的幾個(gè)默認(rèn)的異常處理器就是經(jīng)過這個(gè)方法,但是這個(gè)方式創(chuàng)建出來的bean對象是不歸Spring管理的。
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {return context.getAutowireCapableBeanFactory().createBean(clazz);}
0、常見的默認(rèn)異常處理器
1 SimpleMappingExceptionResolver
基本不用刻意忽略
2 ResponseStatusExceptionResolver
用于處理通過@ResponseStatus注解處理的異常
// 實(shí)現(xiàn)了接口MessageSourceAware,方便拿到國際化資源,方便錯誤消息的國際化
// @since 3.0
public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {@Nullableprivate MessageSource messageSource;@Overridepublic void setMessageSource(MessageSource messageSource) {this.messageSource = messageSource;}@Override@Nullableprotected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {try {// 若異常類型是,那就處理這個(gè)異常// 處理很簡單:response.sendError(statusCode, resolvedReason)// 當(dāng)然會有國際化消息的處理。最終new一個(gè)空的new ModelAndView()供以返回if (ex instanceof ResponseStatusException) {return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler);}// 若異常類型所在的類上標(biāo)注了ResponseStatus注解,就處理這個(gè)狀態(tài)碼//(可見:異常類型優(yōu)先于ResponseStatus)// 處理方式同上~~~~ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);if (status != null) {return resolveResponseStatus(status, request, response, handler, ex);}// 這里有個(gè)遞歸:如果異常類型是Course里面的,也會繼續(xù)處理,所以需要注意這里的遞歸處理if (ex.getCause() instanceof Exception) {return doResolveException(request, response, handler, (Exception) ex.getCause());}} catch (Exception resolveEx) { // 處理失敗,就記錄warn日志(非info哦~)if (logger.isWarnEnabled()) {logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", resolveEx);}}return null;}
}
3 DefaultHandlerExceptionResolver
用于處理Spring MVC自己拋出的一些特定的異常
異常類型 | 狀態(tài)碼 |
---|---|
MissingPathVariableException | 500 |
ConversionNotSupportedException | 500 |
HttpMessageNotWritableException | 500 |
AsyncRequestTimeoutException | 503 |
MissingServletRequestParameterException | 400 |
ServletRequestBindingException | 400 |
TypeMismatchException | 400 |
HttpMessageNotReadableException | 400 |
MethodArgumentNotValidException | 400 |
MissingServletRequestPartException | 400 |
BindException | 400 |
NoHandlerFoundException | 404 |
HttpRequestMethodNotSupportedException | 405 |
HttpMediaTypeNotAcceptableException | 406 |
HttpMediaTypeNotSupportedException | 415 |
// @since 3.0
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {public DefaultHandlerExceptionResolver() {setOrder(Ordered.LOWEST_PRECEDENCE);setWarnLogCategory(getClass().getName()); // 不同的日志采用不同的記錄器是個(gè)很好的習(xí)慣}@Override@Nullableprotected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {try {if (ex instanceof HttpRequestMethodNotSupportedException) {return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request, response, handler);} else if (ex instanceof HttpMediaTypeNotSupportedException) {return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response, handler);} ... // 省略其它的else if// 多有的handle方法幾乎一樣的,都是response.sendError()// 有的還會esponse.setHeader("Accept", MediaType.toString(mediaTypes));等等}
}
4 ExceptionHandlerExceptionResolver
用于處理通過@ExceptionHandler注解處理的方法拋出的異常,這個(gè)異常處理器是用的最多的。
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolverimplements ApplicationContextAware, InitializingBean {。。。。。。。。。。
}
4.0 ExceptionHandlerExceptionResolver
繼承自AbstractHandlerMethodExceptionResolver,該類主要處理Controller中用@ExceptionHandler注解定義的方法。
該類也是配置中定義的HandlerExceptionResolver實(shí)現(xiàn)類之一,大多數(shù)異常處理都是由該類操作。
SpringMVC中如果配置了 mvc:annotation-driven/ 或者就會引入的 HandlerExceptionResolverComposite,
1、argumentResolvers和customArgumentResolvers是參數(shù)解析器,負(fù)責(zé)將HTTP請求數(shù)據(jù)解析成異常處理方法的形參對象。
2、returnValueHandlers和customReturnValueHandlers是返回值處理器,負(fù)責(zé)將異常處理方法的返回值進(jìn)行處理。
3、messageConverters是數(shù)據(jù)轉(zhuǎn)換的底層工具,一方面從HTTP請求中讀取并轉(zhuǎn)換數(shù)據(jù)成對象,另一方面將對象轉(zhuǎn)成HTTP響應(yīng)數(shù)據(jù)。
4、contentNegotiationManager是負(fù)責(zé)媒體內(nèi)容的校驗(yàn),即根據(jù)Content-Tepe進(jìn)行不同處理。
5、responseBodyAdvice是ResponseBodyAdvice的緩存,即支持在異常處理返回值寫到輸出流前的切面處理。
6、applicationContext是Spring上下文,可以從中獲取容器中內(nèi)容。
7、exceptionHandlerCache是異常-異常處理方法的緩存。
8、exceptionHandlerAdviceCache是@ControllerAdvice全局異常處理器的緩存。
4.1 afterPropertiesSet()
在創(chuàng)建這個(gè)ExceptionHandlerExceptionResolver對象的時(shí)候會執(zhí)行他的afterPropertiesSet(),在這方法中會去獲取@ControllerAdvice定義的全局ExceptionHandler方法
@Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beans//初始化 @ControllerAdvice 的 beaninitExceptionHandlerAdviceCache();if (this.argumentResolvers == null) {//獲取 默認(rèn)的參數(shù)解析器 DefaultArgumentResolversList<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {//獲取 默認(rèn)的返回值處理器 DefaultReturnValueHandlersList<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}
4.1.1 initExceptionHandlerAdviceCache()
在nitExceptionHandlerAdviceCache()方法中,會從Spring容器中獲取所有@ControllerAdvice標(biāo)注的bean。遍歷這些bean,將其中@ExceptionHandler標(biāo)注的異常處理方法緩存到exceptionHandlerAdviceCache。如果這些bean實(shí)現(xiàn)了ResponseBodyAdvice接口,還會緩存到responseBodyAdvice:
private void initExceptionHandlerAdviceCache() { // 獲取所有@ControllerAdvice標(biāo)注的beanList<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); for (ControllerAdviceBean adviceBean : adviceBeans) { Class<?> beanType = adviceBean.getBeanType(); if (beanType == null) { throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); } // 構(gòu)造異常-處理方法映射ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType); // 添加exceptionHandlerAdviceCache緩存if (resolver.hasExceptionMappings()) { this.exceptionHandlerAdviceCache.put(adviceBean, resolver); } // 添加responseBodyAdvice緩存if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) { this.responseBodyAdvice.add(adviceBean); } }
}
4.2 getDefaultArgumentResolvers()
protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();// Annotation-based argument resolutionresolvers.add(new SessionAttributeMethodArgumentResolver());resolvers.add(new RequestAttributeMethodArgumentResolver());// Type-based argument resolutionresolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());resolvers.add(new RedirectAttributesMethodArgumentResolver());resolvers.add(new ModelMethodProcessor());// Custom arguments//合并了自定義的參數(shù)解析器if (getCustomArgumentResolvers() != null) {resolvers.addAll(getCustomArgumentResolvers());}// Catch-allresolvers.add(new PrincipalMethodArgumentResolver());return resolvers;}
4.3 getDefaultReturnValueHandlers()
獲取返回值處理器,自此對象創(chuàng)建完成。
protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();// Single-purpose return value typeshandlers.add(new ModelAndViewMethodReturnValueHandler());handlers.add(new ModelMethodProcessor());handlers.add(new ViewMethodReturnValueHandler());handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));// Annotation-based return value typeshandlers.add(new ServletModelAttributeMethodProcessor(false));handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));// Multi-purpose return value typeshandlers.add(new ViewNameMethodReturnValueHandler());handlers.add(new MapMethodProcessor());// Custom return value types//合并了自定義的返回值處理器if (getCustomReturnValueHandlers() != null) {handlers.addAll(getCustomReturnValueHandlers());}// Catch-allhandlers.add(new ServletModelAttributeMethodProcessor(true));return handlers;}
二、異常處理流程源碼分析
1、DispatcherServlet#processDispatchResult()
在DispatcherServlet#doDispatch()處理請求過程中拋出異常,會在DispatcherServlet#processDispatchResult()方法中進(jìn)行異常處理, 如果監(jiān)測到了非ModelAndViewDefiningException異常,會調(diào)用DispatcherServlet#processHandlerException()方法進(jìn)行異常處理:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { try { try { // 文件請求處理processedRequest = checkMultipart(request); // 請求地址映射mappedHandler = getHandler(processedRequest); // 獲取處理器適配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 攔截器預(yù)處理if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 實(shí)際處理請求mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 攔截器后處理mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // 異常處理processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); }
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } }
}
2、processHandlerException()
由于默認(rèn)初始化添加的是HandlerExceptionResolverComposite處理器,所以執(zhí)行的也是當(dāng)前類的resolveException();
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception { // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; if (this.handlerExceptionResolvers != null) { for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) { exMv = resolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } } // ……
}
2.1 HandlerExceptionResolverComposite#resolveException()
public ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { if (this.resolvers != null) { for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) { ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex); if (mav != null) { return mav; } } } return null;
}
2.1.1 AbstractHandlerExceptionResolver的resolveException()
先會調(diào)用其父類AbstractHandlerExceptionResolver的resolveException()方法
public ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { if (shouldApplyTo(request, handler)) { prepareResponse(ex, response); ModelAndView result = doResolveException(request, response, handler, ex); if (result != null) { // Print debug message when warn logger is not enabled. if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) { logger.debug(buildLogMessage(ex, request) + (result.isEmpty() ? "" : " to " + result)); } // Explicitly configured warn logger in logException method. logException(ex, request); } return result; } else { return null; }
}
2.1.1.1 AbstractHandlerMethodExceptionResolver#doResolveException()
進(jìn)行類型轉(zhuǎn)換
protected final ModelAndView doResolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null); return doResolveHandlerMethodException(request, response, handlerMethod, ex);
}
2.1.1.1.1ExceptionHandlerExceptionResolver#doResolveHandlerMethodException()
從緩存中獲取異常對應(yīng)的處理方法,添加argumentResolvers和returnValueHandlers。解析異常作為請求參數(shù),最后調(diào)用異常處理方法進(jìn)行異常處理。
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) { // 從緩存中獲取異常對應(yīng)的處理方法ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception); if (exceptionHandlerMethod == null) { return null; } // 添加argumentResolvers和returnValueHandlersif (this.argumentResolvers != null) { exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } ServletWebRequest webRequest = new ServletWebRequest(request, response); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 遞歸添加拋出的異常,作為請求參數(shù)ArrayList<Throwable> exceptions = new ArrayList<>(); try { if (logger.isDebugEnabled()) { logger.debug("Using @ExceptionHandler " + exceptionHandlerMethod); } // Expose causes as provided arguments as well Throwable exToExpose = exception; while (exToExpose != null) { exceptions.add(exToExpose); Throwable cause = exToExpose.getCause(); exToExpose = (cause != exToExpose ? cause : null); } Object[] arguments = new Object[exceptions.size() + 1]; exceptions.toArray(arguments); // efficient arraycopy call in ArrayList arguments[arguments.length - 1] = handlerMethod; // 調(diào)用異常處理方法進(jìn)行異常處理exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments); } catch (Throwable invocationEx) { return null; } if (mavContainer.isRequestHandled()) { return new ModelAndView(); }
}
其中ExceptionHandlerExceptionResolver#getExceptionHandlerMethod方法,根據(jù)request請求的方法和拋出的異??梢云ヅ涞綄?yīng)的handleMethod。getExceptionHandlerMethod這個(gè)方法可以支持單獨(dú)使用@ExceptionHandler,既使用了@ExceptionHandler又使用了@ControllerAdvice兩種方式。
在ExceptionHandlerExceptionResolver#initExceptionHandlerAdviceCache方法中,ExceptionHandlerExceptionResolver已經(jīng)掃描了所有@ControllerAdvice注解的Bean,并將其封裝成了一個(gè)又一個(gè)的ExceptionHandlerMethodResolver,而構(gòu)造ExceptionHandlerMethodResolver時(shí),ExceptionHandlerMethodResolver就會掃描這個(gè)Bean下所有的@ExceptionHandler注解的方法。
所以可以先匹配這個(gè)controller是否有使用@ExceptionHandler,如果沒有,則從緩存的ControllerAdviceBean中匹配異常。
2.1.1.1.1.1 ServletInvocableHandlerMethod#getExceptionHandlerMethod()
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {//得到controllerClass<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null);if (handlerMethod != null) {//先嘗試從緩存中獲取ExceptionHandlerMethodResolver//ExceptionHandlerMethodResolver有緩存所有`@ExceptionHandler`注解的方法ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);if (resolver == null) {//沒獲取到的話,構(gòu)造一個(gè)并將其放入緩存中resolver = new ExceptionHandlerMethodResolver(handlerType);this.exceptionHandlerCache.put(handlerType, resolver);}//根據(jù)異常獲取對應(yīng)的handler_method//如果不為空,則說明這個(gè)controoler配置了`@ExceptionHandler`Method method = resolver.resolveMethod(exception);if (method != null) {return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);}}//如果controller沒有配置`@ExceptionHandler`,則使用統(tǒng)一配置的`@ControllerAdvice`//遍歷所有的`@ControllerAdvice`,根據(jù)異常匹配對應(yīng)的handler_methodfor (Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {if (entry.getKey().isApplicableToBeanType(handlerType)) {ExceptionHandlerMethodResolver resolver = entry.getValue();Method method = resolver.resolveMethod(exception);//如果匹配倒了,返回這個(gè)methodif (method != null) {return new ServletInvocableHandlerMethod(entry.getKey().resolveBean(), method);}}}return null;
}
2.1.1.1.1.2 ServletInvocableHandlerMethod#invokeAndHandle()
和之前的HandleMapping一眼的處理流程
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {//調(diào)用反射handler_method,拿到handler_method執(zhí)行的結(jié)果`returnValue`Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);//如果這個(gè)handler_method上,還標(biāo)注了`@ResponseStatus`注解//設(shè)置response的http狀態(tài)碼和錯誤原因setResponseStatus(webRequest);//將執(zhí)行結(jié)果保存到ModelAndViewContainer中if (returnValue == null) {if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(this.responseReason)) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);try {//處理執(zhí)行的返回值this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);}catch (Exception ex) {if (logger.isTraceEnabled()) {logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);}throw ex;}
}
3、總結(jié)流程
1、ExceptionHandlerExceptionResolver根據(jù)請求的方法和拋出的異常,匹配對應(yīng)的異常處理方法
2、先匹配controller中有的@ExceptionHandler標(biāo)注了的方法
3、再匹配@ControllerAdvice中的@ExceptionHandler標(biāo)注的方法
4、執(zhí)行異常處理方法,獲取返回值
5、返回值輸出到response中