免费在线a视频-免费在线观看a视频-免费在线观看大片影视大全-免费在线观看的视频-色播丁香-色播基地

面試官:你能給我談?wù)凷pring MVC的異常處理機(jī)制嗎?

:2020年04月02日 Java面試那些事兒
分享到:

# 前言SpringMVC是目前主流的Web MVC框架之一。 本文將分析SpringMVC的異常處理內(nèi)容,讓讀者了解SpringMVC異常處理的設(shè)計(jì)原理。# 重要接口和類(lèi)介紹1. HandlerExceptionResolver接口SpringMVC異...

# 前言

SpringMVC是目前主流的Web MVC框架之一。 

本文將分析SpringMVC的異常處理內(nèi)容,讓讀者了解SpringMVC異常處理的設(shè)計(jì)原理。

# 重要接口和類(lèi)介紹

1. HandlerExceptionResolver接口

SpringMVC異常處理核心接口。該接口定義了1個(gè)解析異常的方法:

ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;

2. AbstractHandlerExceptionResolver抽象類(lèi)

實(shí)現(xiàn)了HandlerExceptionResolver和Ordered接口的抽象類(lèi)。

先看下屬性:

再看下接口的實(shí)現(xiàn):

3. AbstractHandlerMethodExceptionResolver抽象類(lèi)

繼承AbstractHandlerExceptionResolver抽象類(lèi)的抽象類(lèi)。該類(lèi)主要就是為HandlerMethod類(lèi)服務(wù),既handler參數(shù)是HandlerMethod類(lèi)型。

該類(lèi)重寫(xiě)了shouldApplyTo方法:

doResolveException抽象方法的實(shí)現(xiàn)中調(diào)用了doResolveHandlerMethodException方法,該方法也是1個(gè)抽象方法。

4. ExceptionHandlerExceptionResolver類(lèi)

繼承自AbstractHandlerMethodExceptionResolver,該類(lèi)主要處理Controller中用@ExceptionHandler注解定義的方法。

該類(lèi)也是<annotation-driven/>配置中定義的HandlerExceptionResolver實(shí)現(xiàn)類(lèi)之一,大多數(shù)異常處理都是由該類(lèi)操作。

該類(lèi)比較重要,我們來(lái)詳細(xì)講解一下。

首先我們看下這個(gè)類(lèi)的屬性:

再來(lái)看下該類(lèi)的doResolveHandlerMethodException抽象方法的實(shí)現(xiàn):

默認(rèn)的HandlerMethodArgumentResolver集合:

默認(rèn)的HandlerMethodReturnValueHandler集合:

我們進(jìn)入getExceptionHandlerMethod方法看看是如何得到ServletInvocableHandlerMethod的:

我們看到getExceptionHandlerMethod中會(huì)實(shí)例化ExceptionHandlerMethodResolver,我們看看這個(gè)類(lèi)到底是什么東西?

ExceptionHandlerMethodResolver是一個(gè)會(huì)在Class及Class的父類(lèi)集合中找出帶有@ExceptionHandler注解的類(lèi),該類(lèi)帶有key為T(mén)hrowable,value為Method的緩存屬性。

ExceptionHandlerMethodResolver的構(gòu)造過(guò)程:

ExceptionHandlerExceptionResolver處理過(guò)程總結(jié)一下:根據(jù)用戶(hù)調(diào)用Controller中相應(yīng)的方法得到HandlerMethod,之后構(gòu)造ExceptionHandlerMethodResolver,構(gòu)造ExceptionHandlerMethodResolver有2種選擇,1.通過(guò)HandlerMethod拿到Controller,找出Controller中帶有@ExceptionHandler注解的方法(局部) 2.找到@ControllerAdvice注解配置的類(lèi)中的@ExceptionHandler注解的方法(全局)。這2種方式構(gòu)造的ExceptionHandlerMethodResolver中都有1個(gè)key為T(mén)hrowable,value為Method的緩存。之后通過(guò)發(fā)生的異常找出對(duì)應(yīng)的Method,然后調(diào)用這個(gè)方法進(jìn)行處理。這里異常還有個(gè)優(yōu)先級(jí)的問(wèn)題,比如發(fā)生的是NullPointerException,但是聲明的異常有Throwable和Exception,這時(shí)候ExceptionHandlerMethodResolver找Method的時(shí)候會(huì)根據(jù)異常的最近繼承關(guān)系找到繼承深度最淺的那個(gè)異常,即Exception。

5. DefaultHandlerExceptionResolver類(lèi)

繼承自AbstractHandlerExceptionResolver抽象類(lèi)。<annotation-driven/>配置中定義的HandlerExceptionResolver實(shí)現(xiàn)類(lèi)之一。

該類(lèi)的doResolveException方法中主要對(duì)一些特殊的異常進(jìn)行處理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等。

6. ResponseStatusExceptionResolver類(lèi)

繼承自AbstractHandlerExceptionResolver抽象類(lèi)。<annotation-driven/>配置中定義的HandlerExceptionResolver實(shí)現(xiàn)類(lèi)之一。

該類(lèi)的doResolveException方法主要在異常及異常父類(lèi)中找到@ResponseStatus注解,然后使用這個(gè)注解的屬性進(jìn)行處理。

說(shuō)明一下為什么ExceptionHandlerExceptionResolver、DefaultHandlerExceptionResolver、ResponseStatusExceptionResolver是<annotation-driven/>配置中定義的HandlerExceptionResolver實(shí)現(xiàn)類(lèi)。

我們看下<annotation-driven/>配置解析類(lèi)AnnotationDrivenBeanDefinitionParser中部分代碼片段:

這3個(gè)ExceptionResolver最終被會(huì)加入到DispatcherServlet中的handlerExceptionResolvers集合中。

其中ExceptionHandlerExceptionResolver優(yōu)先級(jí)最高,ResponseStatusExceptionResolver第二,DefaultHandlerExceptionResolver第三。

為什么ExceptionHandlerExceptionResolver優(yōu)先級(jí)最高,因?yàn)閛rder屬性值最低

7. @ResponseStatus注解

讓1個(gè)方法或異常有狀態(tài)碼(status)和理由(reason)返回。這個(gè)狀態(tài)碼是http響應(yīng)的狀態(tài)碼。

8. SimpleMappingExceptionResolver類(lèi)

繼承自AbstractHandlerExceptionResolver抽象類(lèi),是1個(gè)根據(jù)配置進(jìn)行解析異常的類(lèi),包括配置異常類(lèi)型,默認(rèn)的錯(cuò)誤視圖,默認(rèn)的響應(yīng)碼,異常映射等配置屬性。本文不分析,有興趣的讀者可自行查看源碼。

# 源碼分析

下面我們來(lái)分析SpringMVC處理異常的源碼。

SpringMVC在處理請(qǐng)求的時(shí)候,通過(guò)RequestMappingHandlerMapping得到HandlerExecutionChain,然后通過(guò)RequestMappingHandlerAdapter得到1個(gè)ModelAndView對(duì)象,這在之前發(fā)生的異常都會(huì)被catch到,然后得到這個(gè)異常并作為參數(shù)傳入到processDispatchResult方法處理。

processDispatchResult方法如下:

processHandlerException方法:

# 實(shí)例講解

接下里講常用ExceptionResolver的實(shí)例。

1. ExceptionHandlerExceptionResolver

@Controller

@RequestMapping(value = "/error")

public class TestErrorController {

@RequestMapping("/exception")

public ModelAndView exception(ModelAndView view) throws ClassNotFoundException {

view.setViewName("index");

throw new ClassNotFoundException("class not found");

}

@RequestMapping("/nullpointer")

public ModelAndView nullpointer(ModelAndView view) {

view.setViewName("index");

String str = null;

str.length();

return view;

}

@ExceptionHandler(RuntimeException.class)

public ModelAndView error(RuntimeException error, HttpServletRequest request) {

ModelAndView mav = new ModelAndView();

mav.setViewName("error");

mav.addObject("param", "Runtime error");

return mav;

}

@ExceptionHandler()

public ModelAndView error(Exception error, HttpServletRequest request, HttpServletResponse response) {

ModelAndView mav = new ModelAndView();

mav.setViewName("error");

mav.addObject("param", "Exception error");

return mav;

}

/**

@ExceptionHandler(NullPointerException.class)

public ModelAndView error(ModelAndView mav) {

mav.setViewName("error");

    mav.addObject("param", "NullPointer error");

return mav;

}*/

}

分析一下:

如果用戶(hù)進(jìn)入nullpointer方法,str對(duì)象還未初始化,會(huì)發(fā)生NullPointerException。如果去掉最后1個(gè)注釋掉的error方法,那么會(huì)報(bào)錯(cuò)。因?yàn)镋xceptionHandlerExceptionResolver的默認(rèn)HandlerMethodArgumentResolver中只有ServletRequestMethodArgumentResolver和ServletResponseMethodArgumentResolver(所以其他2個(gè)error方法中的request和response參數(shù)沒(méi)問(wèn)題)。所以我們給最后1個(gè)error方法加了注釋。

由于TestErrorController控制器中有2個(gè)帶有@ExceptionHandler注解的方法,之前分析的ExceptionHandlerMethodResolver構(gòu)造過(guò)程中,會(huì)構(gòu)造ExceptionHandlerMethodResolver,ExceptionHandlerMethodResolver內(nèi)部會(huì)有1個(gè)key分別為RuntimeException和Exception,value分別為第一個(gè)和第二個(gè)error方法的緩存。由于NullPointerException的繼承關(guān)系離RuntimeException比Exception近,因此最終進(jìn)入了第一個(gè)error方法。

如果用戶(hù)進(jìn)入exception方法,同理。ClassNotFoundException繼承自Exception,跟RuntimeException沒(méi)關(guān)系,那么進(jìn)入第二個(gè)error方法。

說(shuō)明一下,兩個(gè)error方法返回值都是ModelAndView,這是因?yàn)镋xceptionHandlerMethodResolver的默認(rèn)HandlerMethodReturnValueHandler中有ModelAndViewMethodReturnValueHandler。還有其他的比如ModelMethodProcessor、ViewMethodReturnValueHandler和ViewNameMethodReturnValueHandler等。這3個(gè)分別代表返回值Model,View和字符串。有興趣的讀者可自行查看源碼。 

上個(gè)例子是基于Controller的@ExceptionHandler注解方法,每個(gè)Controller都需要寫(xiě)@ExceptionHandler注解方法(寫(xiě)個(gè)BaseController可不用每個(gè)Controller都寫(xiě)單獨(dú)的@ExceptionHandler注解方法)。

ExceptionHandlerMethodResolver內(nèi)部找不到Controller的@ExceptionHandler注解的話(huà),會(huì)找@ControllerAdvice中的@ExceptionHandler注解方法。

因此,我們也可以寫(xiě)1個(gè)ControllerAdvice。

@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;

}

}

此類(lèi)中的error方法代表著全局異常處理方法。

該方法可對(duì)ajax操作進(jìn)行異常處理,我們返回值使用了@ResponseBody進(jìn)行了處理,然后配置json消息轉(zhuǎn)換器即可,這樣該方法響應(yīng)給客戶(hù)端的數(shù)據(jù)就變成了json數(shù)據(jù)。

2. ResponseStatusExceptionResolver

先定義1個(gè)自定義異常:

@ResponseStatus(HttpStatus.UNAUTHORIZED)

public class UnauthorizedException extends RuntimeException {

}

Controller代碼:

@Controller

@RequestMapping(value = "/error")

public class TestErrorController {

@RequestMapping("/unauth")

public ModelAndView unauth(ModelAndView view) {

view.setViewName("index");

throw new UnauthorizedException();

}

}

由于該類(lèi)沒(méi)有寫(xiě)@ExceptionHandler注解,因此ExceptionHandlerExceptionResolver不能解析unauth觸發(fā)的異常。接下來(lái)由ResponseStatusExceptionResolver進(jìn)行解析,由于觸發(fā)的異常UnauthorizedException帶有@ResponseStatus注解。因此會(huì)被ResponseStatusExceptionResolver解析到。最后響應(yīng)HttpStatus.UNAUTHORIZED代碼給客戶(hù)端。HttpStatus.UNAUTHORIZED代表響應(yīng)碼401,無(wú)權(quán)限。關(guān)于其他的響應(yīng)碼請(qǐng)參考HttpStatus枚舉類(lèi)型源碼。

3. DefaultHandlerExceptionResolver

直接上代碼:

@Controller

@RequestMapping(value = "/error")

public class TestErrorController {

@RequestMapping("/noHandleMethod")

public ModelAndView noHandleMethod(ModelAndView view, HttpServletRequest request) throws NoSuchRequestHandlingMethodException {

view.setViewName("index");

throw new NoSuchRequestHandlingMethodException(request);

}

}

用戶(hù)進(jìn)入noHandleMethod方法觸發(fā)NoSuchRequestHandlingMethodException異常,由于沒(méi)配置@ExceptionHandler以及該異常沒(méi)有@ResponseStatus注解,最終由DefaultHandlerExceptionResolver解析,由于NoSuchRequestHandlingMethodException屬于DefaultHandlerExceptionResolver解析的異常,因此被DefaultHandlerExceptionResolver解析。NoSuchRequestHandlingMethodException會(huì)發(fā)生404錯(cuò)誤。

關(guān)于DefaultHandlerExceptionResolver可以處理的其他異常,請(qǐng)參考DefaultHandlerExceptionResolver源碼。

# 擴(kuò)展ExceptionHandlerExceptionResolver功能

SpringMVC提供的HandlerExceptionResolver基本上都能滿(mǎn)足我們的開(kāi)發(fā)要求,因此本文就不準(zhǔn)備寫(xiě)自定義的HandlerExceptionResolver。

既然不寫(xiě)自定義的HandlerExceptionResolver,我們就來(lái)擴(kuò)展ExceptionHandlerExceptionResolver來(lái)吧,讓它支持更多的功能。

比如為ExceptionHandlerExceptionResolver添加更多的HandlerMethodArgumentResolver,ExceptionHandlerExceptionResolver默認(rèn)只能有2個(gè)HandlerMethodArgumentResolver和ServletRequestMethodArgumentResolver(處理ServletRequest、WebRequest、MultipartRequest、HttpSession等參數(shù))和ServletResponseMethodArgumentResolver(處理ServletResponse、OutputStream或Writer參數(shù))。

ModelAndView這種類(lèi)型的參數(shù)會(huì)被ServletModelAttributeMethodProcessor處理。因此我們需要給ExceptionHandlerExceptionResolver添加ServletModelAttributeMethodProcessor這個(gè)HandlerMethodArgumentResolver。由于ServletModelAttributeMethodProcessor處理ModelAndView參數(shù)會(huì)使用WebDataBinderFactory參數(shù),因此我們得重寫(xiě)doResolveHandlerMethodException方法,所以新寫(xiě)了1個(gè)類(lèi)繼承ExceptionHandlerExceptionResolver。

public class MyExceptionHandlerExceptionResolver extends ExceptionHandlerExceptionResolver{

public MyExceptionHandlerExceptionResolver() {

List<HandlerMethodArgumentResolver> list = new ArrayList<HandlerMethodArgumentResolver>();

list.add(new ServletModelAttributeMethodProcessor(true));

this.setCustomArgumentResolvers(list);

}

@Override

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {

ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);

if (exceptionHandlerMethod == null) {

return null;

}

//ServletModelAttributeMethodProcessor 內(nèi)部會(huì)使用傳遞進(jìn)來(lái)的WebDataBinderFactory參數(shù),該參數(shù)由ServletInvocableHandlerMethod提供

exceptionHandlerMethod.setDataBinderFactory(new ServletRequestDataBinderFactory(null, null));

exceptionHandlerMethod.setHandlerMethodArgumentResolvers(getArgumentResolvers());

exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(getReturnValueHandlers());

ServletWebRequest webRequest = new ServletWebRequest(request, response);

ModelAndViewContainer mavContainer = new ModelAndViewContainer();

try {

if (logger.isDebugEnabled()) {

logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);

}

exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);

}

catch (Exception invocationEx) {

logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);

return null;

}

if (mavContainer.isRequestHandled()) {

return new ModelAndView();

}

else {

ModelAndView mav = new ModelAndView().addAllObjects(mavContainer.getModel());

mav.setViewName(mavContainer.getViewName());

if (!mavContainer.isViewReference()) {

mav.setView((View) mavContainer.getView());

}

return mav;

}

}

}

配置:

<bean class="org.format.demo.support.exceptionResolver.MyExceptionHandlerExceptionResolver">

<property name="order" value="-1"/>

</bean>

配置完成之后,然后去掉本文實(shí)例講解中ExceptionHandlerExceptionResolver的代碼,并去掉支持NullPointerException異常的那個(gè)方法的注釋。

測(cè)試如下:

讀者可根據(jù)需求自己實(shí)現(xiàn)其他的擴(kuò)展功能?;蛘邔?shí)現(xiàn)HandlerExceptionResolver接口新寫(xiě)1個(gè)HandlerExceptionResolver實(shí)現(xiàn)類(lèi)。

新的的HandlerExceptionResolver實(shí)現(xiàn)類(lèi)只需在配置文件中定義即可,然后配置優(yōu)先級(jí)。DispatcherServlet初始化HandlerExceptionResolver的時(shí)候會(huì)自動(dòng)尋找容器中實(shí)現(xiàn)了HandlerExceptionResolver接口的類(lèi),然后添加進(jìn)來(lái)。

# 總結(jié)

分析了SpringMVC的異常處理機(jī)制并介紹了幾個(gè)重要的接口和類(lèi),并分析了在<annotation-driven/>中定義的3個(gè)常用的HandlerExceptionResolver。

之后又編寫(xiě)了1個(gè)繼承自ExceptionHandlerExceptionResolver類(lèi)的異常解析類(lèi),鞏固了之前分析的知識(shí)。

希望這篇文章能幫助讀者了解SpringMVC異常機(jī)制。

文中難免有錯(cuò)誤,希望讀者能夠指明出來(lái)。

# 參考資料

  • http://docs.spring.io/spring/docs/4.0.5.RELEASE/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers

[我要糾錯(cuò)]
[ 編輯:王振袢 &發(fā)表于江蘇 ]
關(guān)鍵詞: 前言 SpringMVC 目前 流的 框架

來(lái)源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺(tái),并已注明來(lái)源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請(qǐng)聯(lián)系小編,我們會(huì)及時(shí)審核處理。
聲明:江蘇教育黃頁(yè)對(duì)文中觀點(diǎn)保持中立,對(duì)所包含內(nèi)容的準(zhǔn)確性、可靠性或者完整性不提供任何明示或暗示的保證,不對(duì)文章觀點(diǎn)負(fù)責(zé),僅作分享之用,文章版權(quán)及插圖屬于原作者。

點(diǎn)個(gè)贊
0
踩一腳
0

您在閱讀:面試官:你能給我談?wù)凷pring MVC的異常處理機(jī)制嗎?

Copyright©2013-2025 ?JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢(xún)平臺(tái)保留所有權(quán)利

蘇公網(wǎng)安備32010402000125 蘇ICP備14051488號(hào)-3技術(shù)支持:南京博盛藍(lán)睿網(wǎng)絡(luò)科技有限公司

南京思必達(dá)教育科技有限公司版權(quán)所有   百度統(tǒng)計(jì)

主站蜘蛛池模板: 国产精品高清一区二区三区不卡 | 大又大又黄又爽免费毛片 | 亚洲日韩中文字幕一区 | 欧美日本综合一区二区三区 | 日韩深夜福利视频 | 欧美一级在线全免费 | 国产精品九九视频 | 黄色樱桃试色免费 | 日韩精品在线观看视频 | 国产精品久久成人影院 | 日韩精品第一页 | 成人免费看毛片 | 亚洲成人黄色网 | 你懂得在线观看 | 亚洲国产欧美精品 | 欧美乱操 | 深夜毛片 | 欧美在线成人午夜网站 | 免费福利午夜影视网 | 极品国产高颜值露脸在线 | 野外一级毛片 | 韩国伦理片免费在线观看 | 视频一区二区中文字幕 | 一个人视频资源在线观看www | 日韩一区视频在线 | 日本成人在线播放 | 一级黄色免费观看 | jizzjizz丝袜老师 | 日批在线看 | 国产一区二区三区在线 | 一个人看免费视频www在线观看 | 免费看又黄又爽又猛的视频软件- | 久久综合草 | 东京加勒比中文字幕波多野结衣 | 国产中文99视频在线观看 | 精品五夜婷香蕉国产线看观看 | 国产v综合v亚洲欧美大另类 | 精品国产亚一区二区三区 | 激情五月俺来也 | 国产 中文 制服丝袜 另类 | 老妇毛片 |
最熱文章
最新文章
  • 阿里云上云鉅惠,云產(chǎn)品享最低成本,有需要聯(lián)系,
  • 卡爾蔡司鏡片優(yōu)惠店,鏡片價(jià)格低
  • 蘋(píng)果原裝手機(jī)殼