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

HandlerMapping之RequestMappingHandlerMapping作用詳解

 更新時間:2023年10月12日 09:10:58   作者:Evan_L  
這篇文章主要介紹了HandlerMapping之RequestMappingHandlerMapping作用詳解,HandlerMapping是用來尋找Handler的,并不與Handler的類型或者實現(xiàn)綁定,而是根據(jù)需要定義的,那么為什么要單獨給@RequestMapping實現(xiàn)一個HandlerMapping,需要的朋友可以參考下

前言

上回我們知道HandlerMapping是用來尋找Handler的,并不與Handler的類型或者實現(xiàn)綁定,而是根據(jù)需要定義的。

那么為什么要單獨給@RequestMapping實現(xiàn)一個HandlerMapping?這次咱們就來專門看看這個RequestMappingHandlerMapping。

RequestMappingHandlerMapping

名字來源

因為RequestMappingHandlerMapping是專門為@RequestMapping而生的,因此他的名字是這樣來的:@RequestMapping的HandlerMapping了。

為什么不叫MethodHandlerMapping呢?

主要還是Handler是一個邏輯概念,MethodHandler了只是對目標(biāo)方法進(jìn)行了封裝,并不是真正處理請求的。

真正處理請求的是我們@RequestMapping的方法。取個名字都給你講道理。

@RequestMapping

在解答文章開頭的問題前,我們先看看@RequestMapping

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
	/**
	 * 處理器的名字,支持類級別和方法級別,多個路徑用#分割
	 */
	String name() default "";
	/**
	 * 匹配請求路徑
	 */
	@AliasFor("path")
	String[] value() default {};
	/**
	 * 匹配請求路徑
	 */
	@AliasFor("value")
	String[] path() default {};
	/**
	 * Http請求方法:可選GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE
	 */
	RequestMethod[] method() default {};
	/**
	 * 匹配指定的地址欄參數(shù)
	 */
	String[] params() default {};
	/**
	 * 匹配特定的header
	 */
	String[] headers() default {};
	/**
	 * 匹配特定的Content-Type
	 */
	String[] consumes() default {};
	/**
	 * 匹配特定的Accept
	 */
	String[] produces() default {};
}

發(fā)現(xiàn)了嗎,各位?他除了能根據(jù)URI匹配,還能根據(jù)請求頭、請求方法、甚至是請求參數(shù)來匹配!

上回說的基于URL的兩種HandlerMapping都不能滿足他,因此必須推出一個更加強(qiáng)大、可擴(kuò)展性更強(qiáng)的HandlerMapping——RequestMappingHandlerMapping

在這里插入圖片描述

那么問題來了:

  • @RequestMapping是在什么如何被解析的呢?
    • 我們很容易想到的就是,遍歷容器中所有的對象,檢查是否存在@Controller注解。存在,那就是控制器。然后接著遍歷所有聲明的public方法,檢查是否存在@RequestMapping方法。這樣,我們就找到了處理器方法。
  • @RequestMapping是在什么時候被解析的呢?
    • 本著“誰使用,誰解析”的原則,他自然是被RequestMappingHandlerMapping解析的。而又因為@RequestMapping的尋找可太費功夫,不可能在提供映射服務(wù)時再來解析,只能是初始化時進(jìn)行解析。因此實現(xiàn)InitializingBean進(jìn)行初始化,是個選擇。

沒錯,實際上,SpringMVC跟你想的一樣。在InitializingBean的afterPropertiesSet方法中,完成了以3下件事:

  1. 尋找@Controller的bean,并找到所有的@RequestMapping方法
  2. 解析@RequestMapping封裝成RequestMappingInfo
  3. 將以上解析到的信息進(jìn)行注冊。

信息包括:

信息描述
@Controller/@RequestMapping對象反射調(diào)用目標(biāo)方法時,需要的target對象
RequestMappingInfo由@RequestMapping解析而來
@RequestMapping的方法注冊時,注冊器會將Method與handler對象一起封裝成HandlerMethod進(jìn)行注冊。便于后面適配器調(diào)用。

@RequestMapping的注冊

前面的解析@RequestMapping到RequestMappingInfo,可以省略,比較簡單。但是@RequestMapping的注冊沒辦法省略。因為如果搞不清楚他是怎么注冊的,也就沒辦法理解他是怎么尋找目標(biāo)處理器的。

為了支撐@RequestMapping多樣化的匹配條件,不能再像前面兩款HanderMapping一樣,簡單粗暴的使用Map了。在 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping 的內(nèi)部定義了內(nèi)部類,專門用來做注冊中心,管理映射關(guān)系。

/**
	 * Mapping注冊中心,可以理解為辦事處
	 */
	class MappingRegistry {
		/**
		 * T是匹配條件的對象。MappingRegistration是注冊的信息,可以理解為你要做事情。
		 * 對于RequestMappingHandlerMapping,T就是RequestMappingInfo
		 * MappingRegistration包括信息:RequestMappingInfo、HandlerMethod、directPaths、mappingName、corsConfig
		 */
		private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
		/**
		 * Map<path, RequestMappingInfo>
		 */
		private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
		/**
		 * Map<mappingName, List<HandlerMethod>>
		 */
		private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
	}

從他的屬性,我們可以分析得到如下信息:

  1. 直接通過請求路徑來查找處理器時,需要經(jīng)過pathLookup中轉(zhuǎn)registry,最后拿到MappingRegistration才到達(dá)HandlerMethod.
  2. 直接通過mappingName則可以直接找到HandlerMethod. 不過這個是Spring為了支持 <%@ taglib uri="//www.springframework.org/tags" prefix="s" %> 而提供的。跟我們平時使用沒多大關(guān)系。

但是各位觀眾老爺,pathLookup找到的是一個,而mappingName能找到多個,這是咋回事?誤會啊,pathLookup的value可不是簡單的一個元素,而是多個!他是MultiValueMap,不是我們經(jīng)常看到的地攤貨HashMap。他可以一個key對應(yīng)多個value。

但是為什么會有多個呢?或者說為什么需要保存多個呢? 因為一個Handler可以處理多個請求,如果由多個Handler都能處理某一個請求的時候怎么辦呢?況且SpringMVC還支持通配符匹配。umm…這一幕有點似曾相識,我們的nginx做路由轉(zhuǎn)發(fā)的時候,不是也有類似的問題嗎?這意味著在查找Handler的時候,我們還需要找到最佳的匹配。例如,/*相較于/hello,那肯定是/hello更精確,更合適啦。你看,多嚴(yán)謹(jǐn)!

總結(jié)

由于@RequestMapping支持靈活的請求匹配條件,而不只是簡單的路徑,只能開發(fā)出RequestMappingHandlerMapping進(jìn)行支持。

RequestMappingHandlerMapping是通過InitializingBean進(jìn)行初始化的,在這里完成@RequestMappingHandlerMapping的掃描和解析,以及注冊。

HandlerMethod是在注冊時進(jìn)行封裝的。獲取Handler時,拿到的Handler就是HandlerMethod。

后面的適配器適配的,也是他。

RequestMappingHandlerMapping使用了InitializingBean做初始化,但是當(dāng)我們自己在做初始化的時候,尤其是使用多種初始化方式的時候,應(yīng)當(dāng)要注意Spring的調(diào)用順序,否則有可能發(fā)生NPE,或者獲取不到目標(biāo)屬性的情況。

例如:同時在ApplicationContextAware、InitializingBean、@PostConstruct進(jìn)行初始化。 為此,給大家找了官方的bean的生命周期

在這里插入圖片描述

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

相關(guān)文章

  • Java中資源加載的方法及Spring的ResourceLoader應(yīng)用小結(jié)

    Java中資源加載的方法及Spring的ResourceLoader應(yīng)用小結(jié)

    在Java開發(fā)中,資源加載是一個基礎(chǔ)而重要的操作,這篇文章主要介紹了深入理解Java中資源加載的方法及Spring的ResourceLoader應(yīng)用,本文通過實例代碼演示了通過ClassLoader和Class獲取資源的內(nèi)容,以及使用Spring的ResourceLoader加載多個資源的過程,需要的朋友可以參考下
    2024-01-01
  • SpringBoot中@Transiactional注解沒有效果的解決

    SpringBoot中@Transiactional注解沒有效果的解決

    這篇文章主要介紹了SpringBoot中@Transiactional注解沒有效果的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Spring中的ConversionService源碼解析

    Spring中的ConversionService源碼解析

    這篇文章主要介紹了Spring中的ConversionService源碼解析,ConversionService是類型轉(zhuǎn)換服務(wù)的接口,從名字就可以看出ConverterRegistry是要實現(xiàn)轉(zhuǎn)換器注冊表的接口,添加和移除Converter和GenericConverter,需要的朋友可以參考下
    2023-11-11
  • Java使用Predicate過濾集合中的元素的操作方法

    Java使用Predicate過濾集合中的元素的操作方法

    文章介紹了Java 8中Collection接口新增的removeIf方法,該方法允許通過Predicate條件快速移除集合中不符合條件的元素,與傳統(tǒng)使用Iterator和remove()方法相比,removeIf方法更加簡潔和易讀,文章還提供了使用removeIf方法的示例,需要的朋友可以參考下
    2025-11-11
  • spring如何快速穩(wěn)定解決循環(huán)依賴問題

    spring如何快速穩(wěn)定解決循環(huán)依賴問題

    這篇文章主要介紹了spring如何快速穩(wěn)定解決循環(huán)依賴問題,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Quartz作業(yè)調(diào)度基本使用詳解

    Quartz作業(yè)調(diào)度基本使用詳解

    這篇文章主要為大家介紹了Quartz作業(yè)調(diào)度基本使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Java transient關(guān)鍵字使用小記

    Java transient關(guān)鍵字使用小記

    這篇文章主要為大家詳細(xì)介紹了Java transient關(guān)鍵字的使用方法,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Mybatis實現(xiàn)Mapper動態(tài)代理方式詳解

    Mybatis實現(xiàn)Mapper動態(tài)代理方式詳解

    這篇文章主要為大家詳細(xì)介紹了Mybatis實現(xiàn)Mapper動態(tài)代理方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java NIO ByteBuffer讀取文件方式

    Java NIO ByteBuffer讀取文件方式

    這篇文章主要介紹了Java NIO ByteBuffer讀取文件方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Ubuntu安裝jenkins完成自動化構(gòu)建詳細(xì)步驟

    Ubuntu安裝jenkins完成自動化構(gòu)建詳細(xì)步驟

    Jenkins是一個開源的自動化服務(wù)器,可以用來輕松地建立持續(xù)集成和持續(xù)交付(CI/CD)管道,這篇文章主要給大家介紹了關(guān)于Ubuntu安裝jenkins完成自動化構(gòu)建的相關(guān)資料,需要的朋友可以參考下
    2024-03-03

最新評論

清河县| 桂东县| 高要市| 思南县| 宁武县| 乡城县| 江陵县| 蓬安县| 巴东县| 罗定市| 乐昌市| 扶风县| 沭阳县| 井研县| 嘉义县| SHOW| 普格县| 晋中市| 五峰| 乌拉特中旗| 香河县| 锡林浩特市| 浪卡子县| 镇江市| 旅游| 马龙县| 武山县| 乳源| 水城县| 双柏县| 金塔县| 丰镇市| 晋宁县| 章丘市| 怀安县| 辉县市| 汾阳市| 伊宁县| 忻州市| 东兴市| 色达县|