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

聊聊在獲取方法參數(shù)名方面,Spring真的就比Mybatis強(qiáng)?

 更新時(shí)間:2021年12月16日 09:51:09   作者:KinYang_Lau  
在獲取方法參數(shù)名方面,Spring真的就比Mybatis強(qiáng)嗎?今天就帶大家聊聊這個(gè)話題,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

前言

在使用 Spring MVC 寫(xiě)Controller的時(shí)候,即使不使用注解,只要參數(shù)名和請(qǐng)求參數(shù)的key對(duì)應(yīng)上了,就能自動(dòng)完成數(shù)值的封裝。

但是在使用 Mybatis框架寫(xiě)接口方法向xml里的SQL語(yǔ)句傳參時(shí),必須使用@Param('')指定key值,在SQL中才可以取到。

Spring可以做到,難道Mybatis做不到嗎?難道Mybatis技術(shù)不行?

一、Spring是如何獲取方法參數(shù)名稱的?

Spring框架自己寫(xiě)了一個(gè)工具類(lèi),用來(lái)專門(mén)獲取方法參數(shù)名稱,DefaultParameterNameDiscoverer類(lèi)是一個(gè)聚合類(lèi),維護(hù)了一個(gè)LinkedList集合,里面的是真正處理的業(yè)務(wù)的類(lèi)對(duì)象。

真正處理獲取方法參數(shù)名稱有三種情況:

  • 一種是處理Kotlin的情況(KotlinReflectionParameterNameDiscoverer)
  • 一種是通過(guò)java的反射方式獲?。⊿tandardReflectionParameterNameDiscoverer)
  • 最后是通過(guò)ASM字節(jié)碼方式從LocalVariableTable中獲取(LocalVariableTableParameterNameDiscoverer)
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
	  默認(rèn)添加幾個(gè)參數(shù)名稱獲取的工具
	public DefaultParameterNameDiscoverer() {
		if (KotlinDetector.isKotlinReflectPresent() && !GraalDetector.inImageCode()) {
			addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
		}
		/// add 會(huì)添加到一個(gè) LinkedList 集合中,是一個(gè)有序的集合
		///  所以這里也就是按照優(yōu)先級(jí)進(jìn)行添加的
		 StandardReflectionParameterNameDiscoverer 這個(gè)類(lèi)要求JDK1.8以上的版本,且編譯要加上 -parameters 參數(shù)
		///  其實(shí)就是調(diào)用了  method.getParameters() 方法
		addDiscoverer(new StandardReflectionParameterNameDiscoverer());
		/// LocalVariableTableParameterNameDiscoverer 沒(méi)有jdk版本要求,
		// 是通過(guò)ASM提供的通過(guò)字節(jié)碼獲取方法的參數(shù)名稱
		// 但是依賴 javac 編譯的時(shí)候 添加上 -g 參數(shù)
		addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
	}
}

Spring獲取參數(shù)名稱的兩種方式

1、StandardReflectionParameterNameDiscoverer

這種是通過(guò)java的反射來(lái)后去參數(shù)名稱的。但是通過(guò)反射獲取方法參數(shù)名稱是有前置條件的:

1、要求jdk8以上

2、編譯的時(shí)候,必須加-parameters參數(shù),例如:javac -parameters xxxx.java

只有滿足以上條件編譯出來(lái)的.class,才能通過(guò)反射獲取到方法參數(shù)的名稱。

2、LocalVariableTableParameterNameDiscoverer

這種是通過(guò)ASM框架,解析字節(jié)碼文件來(lái)得到方法參數(shù)名稱的。同樣,此種方法也有前置條件:

1、編譯的時(shí)候,必須添加-g參數(shù),javac -g xxxx.java

兩種方式對(duì)比

可以看出來(lái),spring會(huì)先采用StandardReflectionParameterNameDiscoverer嘗試去獲取參數(shù)名稱

如果獲取不到就嘗試通過(guò)LocalVariableTableParameterNameDiscoverer后去參數(shù)名稱。

通過(guò)java反射獲取參數(shù)名稱的方法,前置條件比較嚴(yán)格,但是獲取方式比較簡(jiǎn)單,直接通過(guò)反射的api調(diào)用就行,不依賴其他三方框架。

而ASM解析字節(jié)碼方式的前置條件相對(duì)比較寬松,只需要編譯的時(shí)候添加 -g參數(shù)就行,缺點(diǎn)就是依賴于ASM框架。(Spring已經(jīng)把a(bǔ)sm框架通過(guò)源碼的形式加入到spring框架中了,所以不需要單獨(dú)在去引用asm框架)

通常,我們

在這里插入圖片描述

二、Mybatis為什么沒(méi)有向Spring學(xué)習(xí)?

Mybatis要獲取的是接口方法的參數(shù)名稱

Mybatis團(tuán)隊(duì)難道不知道ASM技術(shù)嗎?這個(gè)肯定不是。

其實(shí)真正原因在于,Mybatis框架需要獲取的是接口的方法參數(shù)名稱,而Spring需要獲取的是類(lèi)的方法的參數(shù)名稱。這是類(lèi)方法和接口方法是完全不一樣的兩個(gè)東西。

Java 要獲取接口或者抽象方法的參數(shù)的名稱,必須的是JDK8以上,而且編譯的時(shí)候加上-parameters參數(shù),只有這種情況下編譯出來(lái)的.class才能獲取到參數(shù)的名稱。無(wú)論你是通過(guò)java反射還是asm字節(jié)碼技術(shù),前面兩個(gè)條件必須同時(shí)滿足。

所以當(dāng)達(dá)到上述兩個(gè)條件后,直接通過(guò)java的反射就可以直接獲取參數(shù)名稱,根本沒(méi)必要通過(guò)asm技術(shù)去獲取。

所以!Mybatis不是拿不到參數(shù)名稱,而是必須要 jdk8 以上而且還得是-parameters編譯才可以,當(dāng)滿足這兩個(gè)條件的時(shí)候,你也可以不加@Param('')注解。

三、總結(jié)

最后總結(jié)一下:

SpringMVC也不是什么時(shí)候都可以在不借助注解的情況下獲取到參數(shù)名稱,完成自動(dòng)綁定的,只不過(guò)是要到達(dá)的前置條件比較寬松,需要編譯的時(shí)候添加-g參數(shù),而-g這個(gè)參數(shù)一般編譯的時(shí)候都會(huì)加上,因?yàn)橛辛诉@個(gè)參數(shù),在生成的class文件中,添加具體的 line,source,vars 信息。在輸出日志的時(shí)候,才能看到行號(hào)等信息,如果發(fā)生錯(cuò)誤了,就很容易定位。一般在idea這種開(kāi)發(fā)工具中運(yùn)行代碼的時(shí)候,都是默認(rèn)有這個(gè)參數(shù)的。所以你再idea寫(xiě)測(cè)試代碼的時(shí)候,通過(guò)asm總是能獲取到方法的參數(shù)名稱,及時(shí)沒(méi)有設(shè)置-g參數(shù),那是因?yàn)殚_(kāi)發(fā)工具編譯的時(shí)候,就默認(rèn)給你添加了。

不信的話,你可以手動(dòng)編譯一個(gè)java文件,只通過(guò)javac 不添加任何參數(shù),然后運(yùn)行,asm框架也獲取不到方法參數(shù)名稱。

maven打包好像是默認(rèn)都會(huì)加-g參數(shù),所以你碰到的絕大多數(shù)情況,下通過(guò)asm都是可以獲取到參數(shù)名稱的,給人一種asm一定能獲取參數(shù)名稱的錯(cuò)覺(jué)。

所以在使用Spring框架的時(shí)候,一般不用加注解,通常情況下框架也是可以拿到參數(shù)名稱的。

Mybatis,一般情況下都要加注解@Param,是因?yàn)?,Mybatis需要獲取的是接口的方法參數(shù)名稱,要想拿到接口方法的參數(shù)名稱的話,就必須在jdk8以上的環(huán)境下,而且編譯必須加-parameters參數(shù)的時(shí)候才能獲取到,這種情況一般生產(chǎn)環(huán)境下不會(huì)有-parameters參數(shù),所以在寫(xiě)Mybatis的接口的時(shí)候最好加上@Param參數(shù),以保證程序正常運(yùn)行。

四、深入拓展

1、從字節(jié)碼說(shuō)起

java源文件經(jīng)過(guò)java編譯器編譯為.class字節(jié)碼文件,之后才能被JVM執(zhí)行,所以我們可以獲取到的信息都存在.class文件中,但是編譯器編譯.class的的文件默認(rèn)不保留方法參數(shù)名。所以如果只是通過(guò)javac命令不添加任何參數(shù)情況下,編譯出來(lái)的.class文件,是無(wú)論如何也不能獲取到方法的參數(shù)名稱的。

2、看看普通類(lèi)在不同參數(shù)編譯下的.class字節(jié)碼里面都有什么

下面我們通過(guò)javac編譯一個(gè)類(lèi),然后通過(guò)javap 看看里面的內(nèi)容都有什么!

public class TestBean {
    public String myMethod(String helloWord){
        return "";
    }
}

我們分別用三種方式進(jìn)行編譯,然后通過(guò)javap -verbose TestBean.class 進(jìn)行查看

javac TestBean.java
javac -g TestBean.java
javac -parameters TestBean.java

在這里插入圖片描述

從上面截圖可以看出來(lái):

添加-g參數(shù)后,.class會(huì)多出LocalVariableTable的信息,里面可以看到有方法參數(shù)的名字“helloWord”。

添加-parameters參數(shù)后,.class會(huì)多出MethodParameters的信息,里面也可以看到有方法參數(shù)的名字“helloWord”。

而javac不加任何參數(shù)的話,則在任何地方都找不到方法參數(shù)名“helloword”的信息。

所以:也驗(yàn)證了前面所說(shuō)的,默認(rèn)情況下,無(wú)論是asm還是java反射都是無(wú)法獲取方法參數(shù)名稱的,因?yàn)樽止?jié)碼里面就沒(méi)有參數(shù)名的信息。

但是如果是有-g參數(shù)編譯的話,字節(jié)碼里會(huì)在LocalVariableTable將方法的參數(shù)名稱進(jìn)行保存,而ASM框架是基于字節(jié)碼技術(shù)的,所以是可以解析出參數(shù)名稱的。但是java的反射API并未提供獲取LocalVariableTable信息的內(nèi)容,所以-g產(chǎn)生的信息,只能通過(guò)自己解析字節(jié)碼獲取,所以asm是可以做到的。

如果是有-parameters參數(shù)編譯的話,字節(jié)碼里面保存MethodParameters信息,里面就是方法參數(shù)名稱的信息,java的反射api提供的接口可以直接獲取到里面的信息。但是-parameters 是jdk8以后才提供的新特性,所以要想通過(guò)反射api獲取的話,只能是jdk8及以上版本通過(guò)添加-parameters參數(shù)才可以。

3、看看接口在不同參數(shù)編譯下的.class字節(jié)碼里面都有什么

先寫(xiě)一個(gè)普通的接口

public interface TestInterfaceBean {
    public String testInterfaceMethod (String iName);
}

然后再用三種方式進(jìn)行編譯,最后通過(guò)javap -verbose TestInterfaceBean.class 進(jìn)行查看

javac TestInterfaceBean.java
javac -g TestInterfaceBean.java
javac -parameters TestInterfaceBean.java

在這里插入圖片描述

從上面三張截圖可以看出來(lái),只有 javac -parameters 編譯出來(lái)的.class字節(jié)碼文件才帶有 接口方法參數(shù)名的信息,-g 編譯出來(lái)的和默認(rèn)的都是沒(méi)有的。

所以嘛,對(duì)于接口而言,只有通過(guò)-parameters 編譯的字節(jié)碼才能有方法參數(shù)名稱。這也就明白了為什么Mybatis的接口要加注解了吧,因?yàn)槟闳绻煌ㄟ^(guò)注解信息去獲取的話,你不論是java反射也好,asm也好都拿不到參數(shù)名稱,除非你編譯的時(shí)候添加-parameters,而生產(chǎn)環(huán)境通常是不會(huì)加這個(gè)參數(shù)的。

五、結(jié)束

看到這里應(yīng)該弄清楚,獲取參數(shù)名稱的套路了吧!

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

相關(guān)文章

最新評(píng)論