最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringMVC的組件之HandlerExceptionResolver詳解

 更新時(shí)間:2023年10月12日 09:24:32   作者:Evan_L  
這篇文章主要介紹了SpringMVC的組件之HandlerExceptionResolver詳解,不管是在處理請(qǐng)求映射(HandlerMapping),還是在請(qǐng)求被處理(Handler)時(shí)拋出的異常,DispatcherServlet都會(huì)委托給HandlerExceptionResolver進(jìn)行異常處理,該接口只有一個(gè)方法,需要的朋友可以參考下

前言

在介紹完Handler、HandlerAdapter、HandlerMapping之后,剩下的比較關(guān)鍵的組件就是HandlerExceptionResolver、ViewResolver。

其他的像國(guó)際化、主題、文件上傳、重定向,這些錦上添花的組件都是一個(gè)框架需要關(guān)心的。

但不是我們平常使用的核心功能,所以有興趣的同學(xué)就自己了解吧。

HandlerExceptionResolver

不管是在處理請(qǐng)求映射(HandlerMapping),還是在請(qǐng)求被處理(Handler)時(shí)拋出的異常,DispatcherServlet都會(huì)委托給HandlerExceptionResolver進(jìn)行異常處理。

該接口只有一個(gè)方法。

/**
	 * 嘗試處理handler執(zhí)行過程中拋出的異常。可能返回一個(gè)代表特定頁(yè)面的ModelAndView
	 * 如果返回的ModelAndView為空:{ModelAndView#isEmpty()},則表示該異常已經(jīng)被成功處理,并且不需要渲染視圖。例如:通過設(shè)置httpStatus處理異常.
	 * @param request 當(dāng)前HTTP請(qǐng)求
	 * @param response 當(dāng)前HTTP響應(yīng)
	 * @param handler 被執(zhí)行的handler。可能為null,如果異常發(fā)生在處理器選擇之前(例如:multipart處理失敗)
	 * @param ex 處理過程中拋出的異常
	 * @return 對(duì)應(yīng)的ModelAndView。如果無法處理則返回null,DispatcherServlet將使用默認(rèn)的處理流程。返回new ModelAndView(),則說明請(qǐng)求直接被處理完成了,不需要試圖處理。
	 */
	@Nullable
	ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

SpringMVC提供的異常處理器

HandlerExceptionResolverDescription
SimpleMappingExceptionResolver將異常Class簡(jiǎn)單的映射到錯(cuò)誤視圖的名字。常用于瀏覽器應(yīng)用渲染錯(cuò)誤頁(yè)面
DefaultHandlerExceptionResolver負(fù)責(zé)處理SpringMVC拋出的異常,并且將這些異常映射到對(duì)應(yīng)的HTTP狀態(tài)碼??梢詫?duì)照他的替代者:ResponseEntiryExceptionResolver、Controller Advice
ResponseStatusExceptionResolver通過@ResponseStatus注解來處理異常,并基于注解的值映射到HTTP狀態(tài)碼
ExceptionHandlerExceptionResolver.通過調(diào)用@Controller或者@ControllerAdvice中的@ExceptionHandler注解方法來處理異常

接下來,我們介紹一下比較常用的ExceptionHandlerExceptionResolver。

ExceptionHandlerExceptionResolver

如果有同學(xué)配置過全局異常處理的,應(yīng)該會(huì)認(rèn)識(shí)這兩注解:@ControllerAdvice @ExceptionHandler,而他們正是ExceptionHandlerExceptionResolver處理異常的重要抓手。

全局異常配置

在了解ExceptionHandlerExceptionResolver的設(shè)計(jì)之前,我們先來看看最常用的全局異常配置是怎樣的。只有知道他要達(dá)到什么樣的目標(biāo),才能理解他為什么這么設(shè)計(jì)/實(shí)現(xiàn)!

@ControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler(RuntimeException.class)
	@ResponseBody
	public ResultDTO handleRuntimeException(RuntimeException e, HandlerMethod handlerMethod) {
		// ...
	}
	/**
	 * 這是官方的例子
	 */
	@ExceptionHandler({FileSystemException.class, RemoteException.class})
	public ResponseEntity<String> handle(IOException ex) {
    	// ...
	}
}

好,現(xiàn)在來分析一下需求:

  1. 識(shí)別帶@ControllerAdvice注解的bean
  2. 識(shí)別這些bean中的@ExceptionHandler方法
  3. 根據(jù)@ExceptionHandler的條件,找到匹配的異常處理方法
  4. 識(shí)別和處理異常處理方法的參數(shù),并準(zhǔn)備參數(shù)列表 PS: SpringMVC提供了豐富的可選參數(shù)
  5. 識(shí)別和處理方法返回值,并通過response給客戶端進(jìn)行響應(yīng)。

額,有沒有覺得似曾相識(shí)?對(duì)標(biāo)一下@Controller、@RequestMapping?

Handler領(lǐng)域Exception領(lǐng)域作用/描述
@Controller@ControllerAdvice標(biāo)記目標(biāo)處理對(duì)象類
@RestController@RestControllerAdvice標(biāo)記目標(biāo)處理對(duì)象,并表示返回值即為要響應(yīng)的消息體,通常會(huì)被json序列化
@RequestMapping@ExceptionHandler標(biāo)記目標(biāo)處理方法,并且包含方法可以處理的匹配條件
方法參數(shù)列表靈活多變,需要進(jìn)行參數(shù)解析相較于HandlerAdapter,支持的參數(shù)要少一些。例如:不支持@RequestBody參數(shù)方法參數(shù)
方法返回值靈活多變, 需要進(jìn)行返回值處理相較于HandlerAdapter,支持的返回值要少一些。例如不支持ModelAndView,但支持ViewName,不支持異步響應(yīng)返回值等等方法返回值

是不是高度相似?這也意味著他們?cè)趨?shù)解析和返回值處理上高度相似。

異常處理邏輯

與上面的全局異常處理相比,實(shí)際上Spring在處理異常時(shí),還需要考慮@Controller中的@ExceptionHandler方法。

因此異常的處理分為兩部分

處理方法描述
@ControllerAdvice中的@ExceptionHandler這里面的方法是全局性的,所有的@RequestMapping方法只要發(fā)生異常且Controller中沒有聲明異常處理方法,則都會(huì)用這些方法處理
@Controller中的@ExceptionHandler這些異常處理方法則只對(duì)該Controller有效。即,只能處理該Controller中的@RequestMapping方法異常

由此,我們將不得不有個(gè)優(yōu)先級(jí),同樣也是最靠近@RequestMapping優(yōu)先。只有當(dāng)對(duì)應(yīng)的@Controller中沒有@ExceptionHandler時(shí),才能用全局異常處理方法進(jìn)行處理。 但是仔細(xì)考慮一下,在應(yīng)用運(yùn)行過程中,每個(gè)類都是固定的,方法也是固定的,方法有什么注解也是固定的。如果在調(diào)用時(shí)頻繁去使用反射遍歷所有的方法來獲取異常處理方法,是不是不太合理?首先,@Controller類很多時(shí)候都沒有異常處理方法,做這個(gè)遍歷操作純粹是無用功。其次,即使有異常處理方法,每次都遍歷所有方法也不合理,應(yīng)該緩存起來。因此運(yùn)行時(shí)類一般是不會(huì)變的。

Spring的設(shè)計(jì)

因?yàn)椴还苁茾ControllerAdvice還是@Controller,解析@ExceptionHandler的方式都是一樣的,都要遍歷所有方法來尋找。因此可以統(tǒng)一起來。于是抽象出來ExceptionHandlerMethodResolver。先說明,別搞混了哈,我們今天說的ExceptionHandlerExceptionResolver是負(fù)責(zé)調(diào)用ExceptionHandler方法來處理異常的ExceptionResolver[異常處理器],而這個(gè)ExceptionHandlerMethodResolver負(fù)責(zé)解析@ExceptionHandler的MethodResolver[方法解析器],

  • 他負(fù)責(zé)解析管理類中的@ExceptionHandler方法。mappedMethods可以理解為其異常處理方法的注冊(cè)中心。
  • 由于異??梢郧短祝瑸榱思铀倨ヅ?,還搞了一個(gè)緩存exceptionLookupCache。該緩存使用的是Spring的ConcurrentReferenceHashMap,整個(gè)Entry都是軟引用,即發(fā)生OOM異常之前,key、value都會(huì)被清理。(key是異常類型,value是異常處理方法)

ExceptionHandlerExceptionResolver則需要統(tǒng)籌之前說的@ControllerAdvice和@Controller的異常處理。

  • exceptionHandlerCache
    • key是handlerType(HandlerMethod對(duì)應(yīng)的@Controller對(duì)象類型),value是與之對(duì)應(yīng)的ExceptionHandlerMethodResolver
  • exceptionHandlerAdviceCache
    • 緩存@ControllerAdvice對(duì)象的ExceptionHandlerMethodResolver,
    • key是ControllerAdviceBean(他實(shí)際上封裝了@ControllerAdvice的類型信息,同時(shí)也可以通過beanFactory拿到相應(yīng)的bean),value是與該對(duì)象對(duì)應(yīng)的ExceptionHandlerMethodResolver

核心處理邏輯

核心處理邏輯在 ExceptionHandlerExceptionResolver#doResolveHandlerMethodException

/**
	 * 尋找一個(gè)@ExceptionHandler方法并調(diào)用他處理拋出的異常
	 */
	@Override
	@Nullable
	protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
			HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
		// 1. 獲取匹配的異常處理方法,并封裝成ServletInvocableHandlerMethod
		// 就是這個(gè)方法控制著優(yōu)先使用@Controller中的@ExceptionHandler方法
		// 他會(huì)首先檢查exceptionHandlerCache,然后才到exceptionHandlerAdviceCache。他們都是通過ExceptionHandler**Method**Resolver找到目標(biāo)方法的。
		ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
		// 沒有異常處理方法,則直接退出
		if (exceptionHandlerMethod == null) {
			return null;
		}
		// 初始化exceptionHandlerMethod。主要是設(shè)置參數(shù)解析器、返回值處理器
		// 省略...
		// 2. 準(zhǔn)備exceptionHandlerMethod的調(diào)用參數(shù)
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		ArrayList<Throwable> exceptions = new ArrayList<>();
		try {
			// 遍歷嵌套異常作為方法參數(shù)
			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)用exceptionHandlerMethod處理異常
			// 該方法的調(diào)用就跟RequestMappingHandlerAdapter是一樣的了
			exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
		}
		catch (Throwable invocationEx) {
			// 繼續(xù)默認(rèn)的異常處理
			return null;
		}
		if (mavContainer.isRequestHandled()) {
			// 表示異常已被處理完成
			return new ModelAndView();
		}
		else {
			// 從ModelAndViewContainer封裝ModelAndView返回
			// 省略...
			return mav;
		}
	}

總結(jié)

  • 異常處理會(huì)優(yōu)先使用對(duì)應(yīng)的@Controller中的@ExceptionHandler方法,然后才是@ControllerAdvice中的異常處理方法。
  • 從宏觀層面,@ExceptionHandler的緩存分為兩層
層次緩存所在注冊(cè)中心或緩存描述
類層面ExceptionHandlerExceptionResolver管理@ControllerAdvice的exceptionHandlerAdviceCache以及管理@Controller的exceptionHandlerCache每個(gè)BeanType對(duì)應(yīng)一個(gè)ExceptionHandlerMethodResolver
方法層ExceptionHandlerMethodResolver管理@ExceptionHandler方法的mappedMethods。負(fù)責(zé)加速尋找處理方法的exceptionLookupCache每個(gè)類都可能有多個(gè)@ExceptionHandler
  • 方法調(diào)用與RequestMappingHandlerAdapter一樣,都是通過ServletInvocableHandlerMethod進(jìn)行處理。

如果理解了RequestMappingHandlerAdapter那么再來理解這個(gè)ExceptionHandlerExceptionResolver應(yīng)該相對(duì)簡(jiǎn)單些,只需要重點(diǎn)理解兩個(gè)點(diǎn):

  • @ExceptionHandler的出現(xiàn)的位置:@ControllerAdvice和@Controller。
  • @ExceptionHandler的分層設(shè)計(jì)。

到此這篇關(guān)于SpringMVC的組件之HandlerExceptionResolver詳解的文章就介紹到這了,更多相關(guān)HandlerExceptionResolver詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中反射reflect的基礎(chǔ)知識(shí)講解

    Java中反射reflect的基礎(chǔ)知識(shí)講解

    這篇文章主要介紹了Java中反射reflect的基礎(chǔ)知識(shí)講解,Java中的反射,它算是Java當(dāng)中非常底層的一個(gè)技術(shù),平時(shí)我們我們用得不多,實(shí)際上它也的確非常復(fù)雜同時(shí)也難以理解,但是涉及到底層的東西Java都給我們封裝好了,我們直接拿來調(diào)用即可,需要的朋友可以參考下
    2023-10-10
  • Java HashMap的工作原理

    Java HashMap的工作原理

    這篇文章主要介紹了Java HashMap的工作原理的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • Java中的靜態(tài)代碼塊使用解讀

    Java中的靜態(tài)代碼塊使用解讀

    本文將深入探討靜態(tài)代碼塊的工作原理、使用場(chǎng)景以及一些最佳實(shí)踐,幫助你更好地理解和應(yīng)用這一特性
    2025-02-02
  • RocketMQ在Spring Boot上的基礎(chǔ)使用

    RocketMQ在Spring Boot上的基礎(chǔ)使用

    本文主要介紹了RocketMQ在Spring Boot上的基礎(chǔ)使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-03-03
  • Java定義隊(duì)列結(jié)構(gòu),并實(shí)現(xiàn)入隊(duì)、出隊(duì)操作完整示例

    Java定義隊(duì)列結(jié)構(gòu),并實(shí)現(xiàn)入隊(duì)、出隊(duì)操作完整示例

    這篇文章主要介紹了Java定義隊(duì)列結(jié)構(gòu),并實(shí)現(xiàn)入隊(duì)、出隊(duì)操作,結(jié)合完整實(shí)例形式分析了java數(shù)據(jù)結(jié)構(gòu)中隊(duì)列的定義、入隊(duì)、出隊(duì)、判斷隊(duì)列是否為空、打印隊(duì)列元素等相關(guān)操作技巧,需要的朋友可以參考下
    2020-02-02
  • SpringCloud 中使用 Ribbon的方法詳解

    SpringCloud 中使用 Ribbon的方法詳解

    本文重點(diǎn)給大家介紹SpringCloud 中使用 Ribbon的方法,本文通過實(shí)例文字相結(jié)合的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2018-10-10
  • Java中的回調(diào)

    Java中的回調(diào)

    這篇文章主要介紹了Java中回調(diào)的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)java,感興趣的朋友可以了解下
    2020-08-08
  • Spring Boot中利用JavaMailSender發(fā)送郵件的方法示例(附源碼)

    Spring Boot中利用JavaMailSender發(fā)送郵件的方法示例(附源碼)

    這篇文章主要介紹了Spring Boot中利用JavaMailSender發(fā)送郵件的方法示例, 相信使用過Spring的眾多開發(fā)者都知道Spring提供了非常好用的JavaMailSender接口實(shí)現(xiàn)郵件發(fā)送。在Spring Boot的Starter模塊中也為此提供了自動(dòng)化配置。需要的朋友可以參考借鑒。
    2017-02-02
  • 淺談SpringSecurity基本原理

    淺談SpringSecurity基本原理

    今天帶大家了解一下SpringSecurity的基本原理,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • springboot的application.yml配置port不生效的解決方案

    springboot的application.yml配置port不生效的解決方案

    這篇文章主要介紹了springboot的application.yml配置port不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評(píng)論

壶关县| 高陵县| 柞水县| 潍坊市| 三门峡市| 手游| 涪陵区| 宜章县| 子洲县| 隆德县| 金坛市| 抚顺县| 综艺| 阿拉善右旗| 天门市| 建湖县| 达拉特旗| 阳春市| 湄潭县| 武威市| 云阳县| 蒙阴县| 佛教| 河东区| 东兰县| 湖州市| 鄄城县| 宕昌县| 乐昌市| 固镇县| 方山县| 和平区| 明溪县| 通州市| 云浮市| 竹北市| 响水县| 郴州市| 读书| 新安县| 丹巴县|