亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

spring mvc中的@PathVariable動(dòng)態(tài)參數(shù)詳解

 更新時(shí)間:2021年11月01日 09:17:29   作者:cc_yy_zh  
這篇文章主要介紹了spring mvc中的@PathVariable動(dòng)態(tài)參數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

spring mvc @PathVariable動(dòng)態(tài)參數(shù)

spring mvc中的@PathVariable是用來(lái)獲得請(qǐng)求url中的動(dòng)態(tài)參數(shù)的,十分方便

@Controller  
public class TestController {  
     @RequestMapping(value="/user/{userId}/roles/{roleId}",method = RequestMethod.GET)  
     public String getLogin(@PathVariable("userId") String userId,  
         @PathVariable("roleId") String roleId){  
         System.out.println("User Id : " + userId);  
         System.out.println("Role Id : " + roleId);  
         return "hello";  
     }  
     @RequestMapping(value="/product/{productId}",method = RequestMethod.GET)  
     public String getProduct(@PathVariable("productId") String productId){  
           System.out.println("Product Id : " + productId);  
           return "hello";  
     }  
     @RequestMapping(value="/javabeat/{regexp1:[a-z-]+}",  
           method = RequestMethod.GET)  
     public String getRegExp(@PathVariable("regexp1") String regexp1){  
           System.out.println("URI Part 1 : " + regexp1);  
           return "hello";  
     }  
}  

spring mvc是如何做到根據(jù)參數(shù)名動(dòng)態(tài)綁定參數(shù)的?

使用過(guò)SpringMVC的同學(xué)都知道,當(dāng)我們需要在Controller層接收客戶端的請(qǐng)求參數(shù)時(shí),只需要在形參上加@RequestParam注解,SpringMVC就會(huì)自動(dòng)幫我們做參數(shù)綁定,如下示例:

@GetMapping("test1")
public void test1(@RequestParam("name") String name, @RequestParam("age") Integer age) {
}

客戶端請(qǐng)求示例:

curl http://127.0.0.1:8080/test1?name=root&age=18

每個(gè)參數(shù)都加注解寫(xiě)起來(lái)非常的麻煩,因此SpringMVC還可以根據(jù)參數(shù)名自動(dòng)匹配,只要方法的參數(shù)名和客戶端請(qǐng)求的參數(shù)名相同即可綁定,代碼可以簡(jiǎn)化為:

@GetMapping("test2")
public void test2(String name, Integer age) throws Exception {
 
}

SpringMVC是如何做到的呢???

反射獲取參數(shù)名

熟悉SpringMVC的同學(xué)都知道,SpringMVC通過(guò)一個(gè)DispatcherServlet來(lái)分發(fā)客戶端的請(qǐng)求,根據(jù)請(qǐng)求的URI映射對(duì)應(yīng)的處理器Handler,將請(qǐng)求交給對(duì)應(yīng)的Handler處理,說(shuō)白了就是通過(guò)反射的方式調(diào)用Controller的方法,然后將請(qǐng)求的參數(shù)解析,并和方法的形參做匹配并傳遞過(guò)去。

要想綁定參數(shù),首先要做的就是知曉Controller的方法需要的參數(shù)名是什么???

對(duì)于第一種寫(xiě)法,很好理解,方法想要的參數(shù)名就是@RequestParam注解的值,只需要通過(guò)反射來(lái)獲取即可,如下代碼:

public static void main(String[] args) throws Exception {
	Method test1 = UserController.class.getMethod("test1", String.class, Integer.class);
	for (Parameter parameter : test1.getParameters()) {
		RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
		System.err.println("test1-參數(shù)名:" + requestParam.value());
	}
}
控制臺(tái)輸出:
test1-參數(shù)名:name
test1-參數(shù)名:age

但是對(duì)于第二種簡(jiǎn)化的寫(xiě)法,是無(wú)法通過(guò)反射來(lái)獲取參數(shù)名稱的,如下:

public static void main(String[] args) throws Exception {
	Method test2 = UserController.class.getMethod("test2", String.class, Integer.class);
	for (Parameter parameter : test2.getParameters()) {
		System.err.println("test2-參數(shù)名:"+parameter.getName());
	}
}

你們猜猜拿到的參數(shù)名是什么???

在這里插入圖片描述

竟然是沒(méi)有任何意義的arg0、arg1!?。?/p>

這是為什么呢???

熟悉JVM的同學(xué)都知道,Java代碼要想在JVM里執(zhí)行,首先需要通過(guò)javac命令編譯成字節(jié)碼Class文件,而這個(gè)編譯的過(guò)程會(huì)直接將方法的參數(shù)名稱丟棄,變成無(wú)意義的arg0、arg1…,因此通過(guò)反射是無(wú)法獲取參數(shù)名稱的。

-parameters參數(shù)

既然反射獲取不到參數(shù)名是因?yàn)榫幾g時(shí)丟棄了,那么有沒(méi)有辦法讓javac編譯時(shí)將參數(shù)名保留下來(lái)呢???答案是有的,那就是-parameters參數(shù)。

JDK8加入了一個(gè)新功能,編譯時(shí)加上-parameters參數(shù),即可保留參數(shù)名,通過(guò)parameter.getName()就可以獲取到正常的參數(shù)名了。

示例

有如下測(cè)試類:

public class Demo {
 public void test(String name, Integer age) {
 }
}
javac Demo.java #默認(rèn)的編譯方式
javap -verbose Demo

在這里插入圖片描述

javac -parameters Demo.java #加-parameters參數(shù)編譯
javap -verbose Demo

在這里插入圖片描述

可以看到,加了-parameters參數(shù)后,字節(jié)碼文件會(huì)使用額外的MethodParameters區(qū)域來(lái)保存方法的參數(shù)名稱。這樣反射的時(shí)候通過(guò)parameter.getName()就可以獲取到參數(shù)名了。

注意:只支持JDK8及以上版本?。?!

-g參數(shù)

由于-parameters要求JDK至少是8版本,而SpringMVC肯定是要支持低版本JDK的,那么還有沒(méi)有其他方法可以保留參數(shù)名呢???

答案依然是有的,那就是-g參數(shù)。

編譯時(shí),加上-g參數(shù)就是告訴編譯器,我們需要調(diào)試類的信息,這時(shí)編譯器在編譯時(shí),就會(huì)保留局部變量表的信息,參數(shù)也是局部變量表的一部分。

在這里插入圖片描述

可以看到,加上-g后就可以從局部變量表中獲取參數(shù)的名稱了。

使用Maven來(lái)管理項(xiàng)目的話,編譯會(huì)默認(rèn)加-g參數(shù),不需要開(kāi)發(fā)者介入。

注意:雖然-g會(huì)將局部變量表的信息保存下來(lái),但是依然無(wú)法通過(guò)反射parameter.getName()的方式來(lái)獲取參數(shù)名,需要開(kāi)發(fā)者去解析Class字節(jié)碼文件來(lái)獲取,這是和-parameters的一個(gè)重大區(qū)別?。?!

ASM

ASM是一個(gè)通用的Java字節(jié)碼操作和分析框架。 它可以用于修改現(xiàn)有類或直接以二進(jìn)制形式動(dòng)態(tài)生成類。 ASM提供了一些常見(jiàn)的字節(jié)碼轉(zhuǎn)換和分析算法,可以從中構(gòu)建自定義復(fù)雜轉(zhuǎn)換和代碼分析工具。 ASM提供與其他Java字節(jié)碼框架類似的功能,但專注于性能。 因?yàn)樗脑O(shè)計(jì)和實(shí)現(xiàn)盡可能小而且快,所以它非常適合在動(dòng)態(tài)系統(tǒng)中使用(但當(dāng)然也可以以靜態(tài)方式使用,例如在編譯器中)。

編譯時(shí)加上-g參數(shù)可以將參數(shù)名保留下來(lái),但是依然無(wú)法通過(guò)反射來(lái)獲取,需要解析字節(jié)碼文件自己獲取。

有沒(méi)有好用的工具包來(lái)幫我們解析字節(jié)碼文件呢???

答案依然是:有的。

Java通過(guò)ASM就可以很方便的操作字節(jié)碼文件,很多開(kāi)源框架都用到了ASM,例如CGLIB。

下面寫(xiě)一個(gè)例子,通過(guò)ASM來(lái)獲取方法的參數(shù)名。

1、引入依賴

<dependency>
    <groupId>asm</groupId>
    <artifactId>asm-util</artifactId>
    <version>3.3.1</version>
</dependency>

2、代碼示例

public class Demo {
	public void test(String name, Integer age) {
	}
	/**
	 * 通過(guò)ASM來(lái)訪問(wèn)參數(shù)名
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		Class<Demo> clazz = Demo.class;
		Method method = clazz.getMethod("test", String.class, Integer.class);
		InputStream in = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class");
		ClassReader cr = new ClassReader(in);
		ClassNode cn = new ClassNode();
		cr.accept(cn, ClassReader.EXPAND_FRAMES);
		List<MethodNode> methodNodes = cn.methods;
		for (MethodNode methodNode : methodNodes) {
			if (method.getName().equals(methodNode.name)) {
				System.err.println("test方法參數(shù):");
				List<LocalVariableNode> localVariables = methodNode.localVariables;
				for (LocalVariableNode localVariable : localVariables) {
					System.err.println(localVariable.name);
				}
			}
		}
	}
}

控制臺(tái)輸出:

test方法參數(shù):

this

name

age

注意:這種方式對(duì)接口和抽象方法沒(méi)有用,因?yàn)槌橄蠓椒](méi)有方法體,也就沒(méi)有局部變量表。這也就是為什么MyBatis在xml中無(wú)法根據(jù)接口方法的參數(shù)名去綁定參數(shù)的原因!?。?/strong>

至此,我們已經(jīng)知道,Java獲取方法的參數(shù)名有兩種方式,分別是加-parameters參數(shù)反射獲取、-g參數(shù)通過(guò)ASM解析字節(jié)碼文件獲取。

那SpringMVC用的是哪種呢???

SpringMVC的處理方式

SpringMVC是如何解決參數(shù)名稱的問(wèn)題的呢?是通過(guò)-parameters參數(shù)嗎???

當(dāng)然不是,首先-parameters參數(shù)是JDK8才提供的,老版本的JDK根本沒(méi)這個(gè)功能,SpringMVC是要支持JDK8之前的版本的,而且這種解決方案強(qiáng)制要求開(kāi)發(fā)者編譯時(shí)手動(dòng)加參數(shù),也很不友好。

要想知道SpringMVC的解決方案,必須看源碼?。?!

Debug跟蹤源碼的過(guò)程筆者就不詳敘了,感興趣的同學(xué)可以自己去跟蹤一下。

SpringMVC將一個(gè)方法處理器封裝為一個(gè)HandlerMethod類,方法的參數(shù)則用MethodParameter表示:

在這里插入圖片描述

MethodParameter有一個(gè)獲取參數(shù)名的方法getParameterName():

在這里插入圖片描述

獲取參數(shù)名的的任務(wù)其實(shí)是交給ParameterNameDiscoverer去完成了,這是一個(gè)接口,主要的作用就是解析方法的參數(shù)名稱。

MethodParameter的ParameterNameDiscoverer實(shí)現(xiàn)類是PrioritizedParameterNameDiscoverer。

在這里插入圖片描述

距離真相只剩一步之遙了,去看看LocalVariableTableParameterNameDiscoverer實(shí)現(xiàn)吧。

在這里插入圖片描述

只要看inspectClass()方法就知道真相了。

在這里插入圖片描述

可以看到,LocalVariableTableParameterNameDiscoverer底層就是用的ASM的技術(shù)來(lái)獲取方法的參數(shù)名的。只是Spring并沒(méi)有直接依賴ASM,而是將他們封裝到了自己的org.springframework.asm包下。

總結(jié)

SpringMVC獲取Controller方法的參數(shù)名有三種方式,如下:

方案 限制 優(yōu)缺點(diǎn)
參數(shù)加注解 不受限 編寫(xiě)麻煩
-parameters JDK8及以上才支持 直接通過(guò)parameter.getName()獲取,方便
-g 不受限,編譯加-g參數(shù)即可 解析比較麻煩,依賴于ASM
  • 如果加了@RequestParam則優(yōu)先使用注解解析。
  • 如果沒(méi)有注解,則采用StandardReflectionParameterNameDiscoverer解析,通過(guò)Parameter.getName()反射獲取,前提是JDK版本為8以上,且開(kāi)啟了-parameters編譯參數(shù)。
  • 如果前面2種都無(wú)法獲取,則采用LocalVariableTableParameterNameDiscoverer通過(guò)ASM技術(shù)來(lái)解析。

注意:如果編譯不加-g參數(shù),即使是用ASM也無(wú)法解析,巧婦難為無(wú)米之炊?。?!

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • spring cloud-給Eureka Server加上安全的用戶認(rèn)證詳解

    spring cloud-給Eureka Server加上安全的用戶認(rèn)證詳解

    這篇文章主要介紹了spring cloud-給Eureka Server加上安全的用戶認(rèn)證詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • 淺談Spring中單例Bean是線程安全的嗎

    淺談Spring中單例Bean是線程安全的嗎

    這篇文章主要介紹了淺談Spring中單例Bean是線程安全的嗎?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • Java通過(guò)MyBatis框架對(duì)MySQL數(shù)據(jù)進(jìn)行增刪查改的基本方法

    Java通過(guò)MyBatis框架對(duì)MySQL數(shù)據(jù)進(jìn)行增刪查改的基本方法

    MyBatis框架由Java的JDBC API進(jìn)一步封裝而來(lái),在操作數(shù)據(jù)庫(kù)方面效果拔群,接下來(lái)我們就一起來(lái)看看Java通過(guò)MyBatis框架對(duì)MySQL數(shù)據(jù)進(jìn)行增刪查改的基本方法:
    2016-06-06
  • Java搜索與圖論之DFS和BFS算法詳解

    Java搜索與圖論之DFS和BFS算法詳解

    DFS指在進(jìn)行算法運(yùn)算時(shí),優(yōu)先將該路徑的當(dāng)前路徑執(zhí)行完畢,執(zhí)行完畢或失敗后向上回溯嘗試其他途徑。BFS指在進(jìn)行算法運(yùn)算時(shí),優(yōu)先將當(dāng)前路徑點(diǎn)的所有情況羅列出來(lái),然后根據(jù)羅列出來(lái)的情況羅列下一層。本文介紹了二者的實(shí)現(xiàn)與應(yīng)用,需要的可以參考一下
    2022-11-11
  • Springboot2.1.6集成activiti7出現(xiàn)登錄驗(yàn)證的實(shí)現(xiàn)

    Springboot2.1.6集成activiti7出現(xiàn)登錄驗(yàn)證的實(shí)現(xiàn)

    這篇文章主要介紹了Springboot2.1.6集成activiti7出現(xiàn)登錄驗(yàn)證的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java Web開(kāi)發(fā)中過(guò)濾器和監(jiān)聽(tīng)器使用詳解

    Java Web開(kāi)發(fā)中過(guò)濾器和監(jiān)聽(tīng)器使用詳解

    這篇文章主要為大家詳細(xì)介紹了Java中的過(guò)濾器Filter和監(jiān)聽(tīng)器Listener的使用以及二者的區(qū)別,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2022-10-10
  • JavaMail實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送

    JavaMail實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送

    這篇文章主要為大家詳細(xì)介紹了JavaMail實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 詳解Java的線程狀態(tài)

    詳解Java的線程狀態(tài)

    本文主要為大家詳細(xì)介紹一下Java的線程狀態(tài),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的幫助,感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下
    2022-11-11
  • Spring中bean的生命周期之getSingleton方法

    Spring中bean的生命周期之getSingleton方法

    今天給大家?guī)?lái)的是關(guān)于Spring的相關(guān)知識(shí),文章圍繞著Spring中bean的生命周期之getSingleton方法展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Springboot引用外部配置文件的方法步驟

    Springboot引用外部配置文件的方法步驟

    這篇文章主要介紹了Springboot引用外部配置文件的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論