這篇文章主要介紹了SpringFramework之ControllerAdvice注解怎么用,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
站在用戶的角度思考問題,與客戶深入溝通,找到湯陰網(wǎng)站設(shè)計(jì)與湯陰網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站設(shè)計(jì)、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、空間域名、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋湯陰地區(qū)。
SpringFramework版本5.0.9.release。
我們會通過@ControllerAdvice和@ExceptionHandler來處理異常,Springmvc是如何進(jìn)行處理的呢?
ControllerAdviceBean有個(gè)重要的方法findAnnotatedBeans,如下List-1
List-1
public class ControllerAdviceBean implements Ordered { ... public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext applicationContext) { List<ControllerAdviceBean> beans = new ArrayList(); String[] var2 = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class); int var3 = var2.length; for(int var4 = 0; var4 < var3; ++var4) { String name = var2[var4]; if (applicationContext.findAnnotationOnBean(name, ControllerAdvice.class) != null) { beans.add(new ControllerAdviceBean(name, applicationContext)); } } return beans; } ...
如List-1所示,從applicationContext中獲取所有的ControllerAdvice注解的Bean,之后封裝到ControllerAdviceBean中。
來看下ExceptionHandlerExceptionResolver,它的類繼承圖如下圖1所示:
圖1
ExceptionHandlerExceptionResolver是HandlerExceptionResolver,所以在Springmvc的doDispatch中會調(diào)用它。實(shí)現(xiàn)了InitializingBean,所以有afterPropertiesSet方法,如下List-2所示:
List-2
@Override public void afterPropertiesSet() { // Do this first, it may add ResponseBodyAdvice beans initExceptionHandlerAdviceCache(); ... } private void initExceptionHandlerAdviceCache() { ... List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); AnnotationAwareOrderComparator.sort(adviceBeans); for (ControllerAdviceBean adviceBean : adviceBeans) { Class<?> beanType = adviceBean.getBeanType(); if (beanType == null) { throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); } ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType); if (resolver.hasExceptionMappings()) { this.exceptionHandlerAdviceCache.put(adviceBean, resolver); if (logger.isInfoEnabled()) { logger.info("Detected @ExceptionHandler methods in " + adviceBean); } } if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) { this.responseBodyAdvice.add(adviceBean); if (logger.isInfoEnabled()) { logger.info("Detected ResponseBodyAdvice implementation in " + adviceBean); } } } }
List-2中,initExceptionHandlerAdviceCache方法調(diào)用List-1中ControllerAdviceBean的findAnnotatedBeans方法,獲取所有ControllerAdvice的bean,之后排序,所以當(dāng)有多個(gè)ControllerAdivce注解的類且需要排序時(shí),可以實(shí)現(xiàn)spring的Order接口來實(shí)現(xiàn)。
之后遍歷ControllerAdviceBean,之后獲取Bean的class類,傳入到ExceptionHandlerMethodResolver的構(gòu)造方法中,如下List-3所示:
List-3
public class ExceptionHandlerMethodResolver { ... public static final MethodFilter EXCEPTION_HANDLER_METHODS = method -> (AnnotationUtils.findAnnotation(method, ExceptionHandler.class) != null); ... private final Map<Class<? extends Throwable>, Method> mappedMethods = new HashMap<>(16); ... public ExceptionHandlerMethodResolver(Class<?> handlerType) { for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) { for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) { addExceptionMapping(exceptionType, method); } } } ... private List<Class<? extends Throwable>> detectExceptionMappings(Method method) { List<Class<? extends Throwable>> result = new ArrayList<>(); detectAnnotationExceptionMappings(method, result); if (result.isEmpty()) { for (Class<?> paramType : method.getParameterTypes()) { if (Throwable.class.isAssignableFrom(paramType)) { result.add((Class<? extends Throwable>) paramType); } } } if (result.isEmpty()) { throw new IllegalStateException("No exception types mapped to " + method); } return result; } protected void detectAnnotationExceptionMappings(Method method, List<Class<? extends Throwable>> result) { ExceptionHandler ann = AnnotationUtils.findAnnotation(method, ExceptionHandler.class); Assert.state(ann != null, "No ExceptionHandler annotation"); result.addAll(Arrays.asList(ann.value())); } private void addExceptionMapping(Class<? extends Throwable> exceptionType, Method method) { Method oldMethod = this.mappedMethods.put(exceptionType, method); if (oldMethod != null && !oldMethod.equals(method)) { throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for [" + exceptionType + "]: {" + oldMethod + ", " + method + "}"); } }
找到方法上有ExceptionHandler注解的方法。
detectExceptionMappings方法獲取ExceptionHandler的value值,如果我們沒有設(shè)置ExceptionHandler的value,那么遍歷方法的參數(shù),如果參數(shù)是Throwable的子類,就將改類型放入result中,所以由此可知道,我們可以不設(shè)置ExceptionHandler的value,只需要將方法的參數(shù)設(shè)置為Throwable的子類即可,spring會自動識別。
addExceptionMapping方法將結(jié)果放入mappedMethods這個(gè)map中,key是Throwable,而value則是method。
再回到List-2中,initExceptionHandlerAdviceCache方法中,將構(gòu)造好的ControllerAdviceBean和ExceptionHandlerMethodResolver放入到exceptionHandlerAdviceCache(是個(gè)map)中。
HandlerExceptionResolver是個(gè)接口,如下List-4所示:
List-4
public interface HandlerExceptionResolver { @Nullable ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex); }
AbstractHandlerExceptionResolver.resolveException->AbstractHandlerMethodExceptionResolver.doResolveException->ExceptionHandlerExceptionResolver.doResolveHandlerMethodException。
接下來,來看Springmvc中是如何處理我們的ControllerAdvice的。
DispatcherServlet中,doDispatch()->processDispatchResult()->processHandlerException(),如下List-5所示,會遍歷HandlerExceptionResovler來處理。
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception { ModelAndView exMv = null; if (this.handlerExceptionResolvers != null) { for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } }
ExceptionHandlerExceptionResolver是如何加入到Springmvc中handlerExceptionResolvers的,是因?yàn)镈ispatcherServlet.properties中HandlerExceptionResolver的值有ExceptionHandlerExceptionResolver,所以會被Spring自動加入進(jìn)去。
Spring通過上面的方式,將捕獲到的異常交給ExceptionHandlerExceptionResolver.doResolveHandlerMethodException來處理,通過多次轉(zhuǎn)換,最終調(diào)用我們設(shè)置帶有ExceptionHandler注解的方法。
通過源碼分析,帶有ControllerAdvice和ExceptionHandler注解的攔截處理的執(zhí)行先于HandlerInterceptor的afterCompletion。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“SpringFramework之ControllerAdvice注解怎么用”這篇文章對大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
文章名稱:SpringFramework之ControllerAdvice注解怎么用
網(wǎng)站URL:http://m.newbst.com/article30/jegspo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、App設(shè)計(jì)、全網(wǎng)營銷推廣、關(guān)鍵詞優(yōu)化、企業(yè)網(wǎng)站制作、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)