Java通過(guò)反射獲取方法參數(shù)名的方式小結(jié)
1、前言
一般當(dāng)我們用類似下面的反射去獲取方法參數(shù)名時(shí)得到的一般是 arg0、arg1, 參數(shù)名默認(rèn)會(huì)丟失, 導(dǎo)致無(wú)法獲取到真實(shí)的方法參數(shù)名,下面介紹如何通過(guò)其他方式解決。
class A {
void getUser(String userName, String userId){}
}
Method method = A.class.getMethod(String.class,String.class);
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
String name = parameter.getName();
System.out.println(name); // 得到的是arg0, arg1 而非 userName、userId
}2、解決方式
方式2.1: 添加編譯參數(shù)配置 -parameters
java默認(rèn)在編譯工程代碼為class文件時(shí),會(huì)將方法參數(shù)名擦除,替換成arg0、arg1之類。但是我們可以在編譯時(shí)配置將參數(shù)名也一并編譯進(jìn)去,在maven中新增如下編譯插件配置
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- 配置編譯時(shí)將方法參數(shù)名保留 -->
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
對(duì)于較新的 maven 版本(>= 3.6.2), 也可以直接使用 parameters 配置項(xiàng):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
添加-parameters的編譯參數(shù)后,可以看到我們編譯后的class文件是源碼的參數(shù)名,而非原來(lái)的arg0、arg1。 之后我們用原生的反射Parameter.getName() 就可以獲取到的方法參數(shù)的真實(shí)參數(shù)名了
注意: 該方式僅對(duì)JDK8及以上版本有效, 以前版本JDK沒(méi)有提供該保留機(jī)制
方式2.2: 使用Spring的內(nèi)部工具類 - ParameterNameDiscoverer
如果正好你的項(xiàng)目依賴了spring,則可以直接使用spring的內(nèi)部工具類ParameterNameDiscoverer去獲取到方法真實(shí)參數(shù)名。ParameterNameDiscoverer的實(shí)現(xiàn)類 主要包含 LocalVariableTableParameterNameDiscoverer、StandardReflectionParameterNameDiscoverer 。 下面介紹如何使用
1、StandardReflectionParameterNameDiscoverer的使用
該發(fā)現(xiàn)器需要與 方式2.1: 添加編譯參數(shù)配置 -parameters 一樣添加編譯配置, 因?yàn)榈讓右彩侵苯佑梅瓷銹arameter去獲取而已
// 創(chuàng)建參數(shù)名發(fā)現(xiàn)器 ParameterNameDiscoverer discoverer = new StandardReflectionParameterNameDiscoverer(); Method method = A.class.getMethod(String.class,String.class); // 獲取方法真實(shí)參數(shù)名. userName, userId String[] parameterNames = discoverer.getParameterNames(method);
2、LocalVariableTableParameterNameDiscoverer的使用
// 創(chuàng)建參數(shù)名發(fā)現(xiàn)器 ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); Method method = A.class.getMethod(String.class,String.class); // 獲取方法真實(shí)參數(shù)名. userName, userId String[] parameterNames = discoverer.getParameterNames(method);
該發(fā)現(xiàn)器底層原理是在編譯類時(shí)生成一個(gè)調(diào)試信息的局部變量表LocalVariableTable,然后基于ASM字節(jié)碼技術(shù)去解析LocalVariableTable得到參數(shù)名, 所以它也需要在編譯時(shí)額外添加 編譯配置, 請(qǐng)?jiān)趍aven中添加如下-g的編譯參數(shù)配置
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<!-- 生成局部變量表 -->
<arg>-g:vars</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
該方法優(yōu)點(diǎn)是JDK8以下版本也能使用,但是缺點(diǎn)是無(wú)法獲取到接口的方法參數(shù)名
3、DefaultParameterNameDiscoverer的使用
// 創(chuàng)建參數(shù)名發(fā)現(xiàn)器 ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); Method method = A.class.getMethod(String.class,String.class); // 獲取方法真實(shí)參數(shù)名. userName, userId String[] parameterNames = discoverer.getParameterNames(method);
這個(gè)參數(shù)名發(fā)現(xiàn)器是一個(gè)組合模式的發(fā)現(xiàn)器, 本身不去實(shí)現(xiàn)獲取參數(shù)名的邏輯,而是組合其他參數(shù)名發(fā)現(xiàn)器, 然后迭代調(diào)用每個(gè)參數(shù)名發(fā)現(xiàn)器直到找到真實(shí)參數(shù)名。 從下面源碼來(lái)看 主要內(nèi)置了前面講到的兩種StandardReflectionParameterNameDiscoverer 和 LocalVariableTableParameterNameDiscoverer。 所以如果要讓對(duì)應(yīng)的參數(shù)名發(fā)現(xiàn)器生效,需要配合對(duì)應(yīng)發(fā)現(xiàn)器的使用邏輯 否則一樣無(wú)法獲取到方法參數(shù)名。
// 源碼
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
public DefaultParameterNameDiscoverer() {
if (!GraalDetector.inImageCode()) {
if (KotlinDetector.isKotlinReflectPresent()) {
addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
}
addDiscoverer(new StandardReflectionParameterNameDiscoverer()); // 依賴編譯參數(shù) -parameters
addDiscoverer(new LocalVariableTableParameterNameDiscoverer()); // // 依賴編譯參數(shù) -g
}
}
}使用總結(jié)
1、參數(shù)名獲取的本質(zhì)
- 所有方案都依賴編譯時(shí)保留參數(shù)名信息(通過(guò)-parameters或-g參數(shù)), 所以編譯的時(shí)候有就是有,沒(méi)有就是沒(méi)有,尤其是一些第三方依賴的類
- 如果是第三方依賴的類若未攜帶調(diào)試信息(如未使用上述編譯參數(shù)進(jìn)行編譯),則無(wú)論如何也是無(wú)法獲取真實(shí)參數(shù)名, 除非第三方庫(kù)已使用-parameters編譯,仍可通過(guò)反射獲?。ǖ珜?shí)際場(chǎng)景較少見(jiàn))
2、版本適配建議
- JDK8+項(xiàng)目: 優(yōu)先使用
-parameters編譯參數(shù)(性能最佳), 配合StandardReflectionParameterNameDiscoverer - JDK7及以下: 使用
-g編譯參數(shù), 配合LocalVariableTableParameterNameDiscoverer - Spring項(xiàng)目: 推薦使用
DefaultParameterNameDiscoverer(自動(dòng)適配最優(yōu)策略), 可同時(shí)配置兩種編譯參數(shù)提升兼容性:
3、在一些springBoot 2.0以后版本中spring-boot-starter-parent會(huì)內(nèi)置了編譯參數(shù)配置,所以不用配也可以直接使用ParameterNameDiscoverer, 當(dāng)然需要確保項(xiàng)目是否覆蓋了默認(rèn)配置導(dǎo)致失效,需要重新配
知名應(yīng)用場(chǎng)景舉例
- spring-mvc 的 @RequestParam 參數(shù)名的可省略配置
- mybatis 的 @Param 也可以不用配置
到此這篇關(guān)于Java通過(guò)反射獲取方法參數(shù)名的方式小結(jié)的文章就介紹到這了,更多相關(guān)Java反射獲取方法參數(shù)名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中l(wèi)ist.contains()的用法及拓展
List集合相信大家在開(kāi)發(fā)過(guò)程中幾乎都會(huì)用到,有時(shí)候難免會(huì)遇到集合里的數(shù)據(jù)是重復(fù)的,需要進(jìn)行去除,下面這篇文章主要給大家介紹了關(guān)于Java中l(wèi)ist.contains()的用法及拓展的相關(guān)資料,需要的朋友可以參考下2023-03-03
Java數(shù)據(jù)庫(kù)連接_jdbc-odbc橋連接方式(詳解)
下面小編就為大家?guī)?lái)一篇Java數(shù)據(jù)庫(kù)連接_jdbc-odbc橋連接方式(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
spring task @Scheduled注解各參數(shù)的用法
這篇文章主要介紹了spring task @Scheduled注解各參數(shù)的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
idea中報(bào)錯(cuò)不支持發(fā)行版本問(wèn)題及解決
在使用Spring框架進(jìn)行項(xiàng)目開(kāi)發(fā)時(shí),有時(shí)會(huì)遇到因JDK版本不一致導(dǎo)致的項(xiàng)目運(yùn)行錯(cuò)誤,解決此問(wèn)題的方法主要有兩步:首先,確保項(xiàng)目的Project和Modules設(shè)置中的JDK版本一致;其次,在IDE的Settings中找到Java?Compiler2024-11-11
springboot2.3 整合mybatis-plus 高級(jí)功能及用法詳解
這篇文章主要介紹了springboot2.3 整合mybatis-plus 高級(jí)功能,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Java基于Luhn算法實(shí)現(xiàn)銀行卡卡號(hào)格式校驗(yàn)詳解
在金融行業(yè),特別是涉及到銀行卡處理的場(chǎng)景中,確保銀行卡號(hào)的有效性是至關(guān)重要的,本文將詳細(xì)介紹如何使用Java實(shí)現(xiàn)基于Luhn算法的銀行卡卡號(hào)格式校驗(yàn),有需要的可以了解下2026-01-01

