欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

論java如何通過反射獲得方法真實參數(shù)名及擴展研究

 更新時間:2022年01月26日 15:07:58   作者:since1986  
這篇文章主要為大家介紹了java如何通過反射獲得方法的真實參數(shù)名以及擴展研究,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進步早日升職加薪

前言

前段時間,在做一個小的工程時,遇到了需要通過反射獲得方法真實參數(shù)名的場景,在這里我遇到了一些小小的問題,后來在部門老大的指導下,我解決了這個問題。通過解決這個問題,附帶著我了解到了很多新的知識,我覺得有必要和大家分享交流一下。

示例

咱們先來看這樣一個小的demo:

這是一個很簡單的小demo,里面就是一個簡簡單單的類Test1,Test1有一個包含兩個參數(shù)的方法test,在Test1main方法中通過射來獲得test方法的所有參數(shù)的名字,并將其輸出到標準流。我本以為這個demo的運行結果會得到方法的參數(shù)名。

結果

驚不驚喜,意不意外?和說好的不一樣??!

咱們先停一下,先把為什么反射沒有拿到正確的值放到一邊,先說說我為什么要研究“通過反射原理獲得方法參數(shù)的實際名稱”這件事呢:是因為我想仿照并實現(xiàn)Spring MVC中的“自動綁定”功能。大家知道Spring MVC里有一個“自動綁定”的功能,能夠自動綁定請求參數(shù)的值到@RequestMapping方法的參數(shù)上的,而不用任何額外的操作。

這個功能我覺得很方便,所以我想嘗試自己仿造這個功能,然后用在公司的項目開發(fā)中。我猜測Spring是通過反射獲得方法的參數(shù)名后根據(jù)參數(shù)名到requestgetParam(String name)來獲得實際的值然后綁定的。因此我就嘗試著按照這個思路做,結果就遇到了上邊提到的反射獲得不了參數(shù)實際名稱的問題。我將這個問題請教了老大,老大了解到我的意圖后,經(jīng)過驗證,得出結論:Spring MVC能不能正常使用自動綁定是與java編譯器編譯時加不加-g參數(shù)有關的,而這個-g參數(shù)是代表著java編譯器在編譯時是否會輸出調試信息。

調試

其實也就是說:Spring是通過讀取java編譯器生成的調試信息從而獲得的方法中參數(shù)的真實名稱的。說到這里,這個問題基本也解決了,但是我還是想再多說一點我后續(xù)的學習結果。后續(xù)我研究了一下Spring對于方法參數(shù)這塊的處理邏輯,也就是對于“自動綁定”功能的底層的實現(xiàn)。

那么,Spring 到底是用了什么“黑科技”來做到獲得方法實際參數(shù)名的呢,咱們不妨就看Spring的源碼吧,看看Spring到底是如何實現(xiàn)的。

Spring源碼

Spring海量的源代碼,從何看起呢,這里,我是這樣解決的:我大體知道這個獲得方法實際參數(shù)名的操作應當和MethodgetParameters()方法有關,或者說它的方法里或許會調用到這個方法,那么好了,我們可以使用idea提供的“查看調用棧”的功能,來順藤摸瓜,看看在Spring中有沒有調用到這個方法,如果有,那么解決方案應當就在調用方法的附近。

我們可以看到,果不其然,在調用棧里就有org.spring包中的方法,其中有兩個方法都是StandardReflectionParameterNameDiscoverer類的方法,其實我們已經(jīng)找到了,看這個類的名字就能知道,它是處理ParameterName的Discoverer的(在這里我想再說點題外話,我個人非常贊同Spring這種全命名的編碼風格,看到命名就能看明白這個類是在干什么,所以說代碼應當是能“自描述”的)

注釋

好,我們再回到代碼中來,繼續(xù)看這個類:發(fā)現(xiàn)它有一段簡要的注釋:

大意就是這個類是針對使用了JDK8基于-parameters編譯參數(shù)的ParameterNameDiscoverer的實現(xiàn),這里這個-parameters參數(shù)是怎么回事咱們先放一邊。

實現(xiàn)接口類

繼續(xù)向上看StandardReflectionParameterNameDiscoverer所實現(xiàn)的這個接口ParameterNameDiscoverer,打開ParameterNameDiscoverer這個接口,我們用idea的查看子類的功能,能夠看到它一共有包括StandardReflectionParameterNameDiscoverer在內的8個子類

其中有一個名字里帶“Default”的子類DefaultParameterNameDiscoverer,按照一般套路來說,帶Default的都是默認的實現(xiàn),那么好了我們優(yōu)先看它吧。

打開DefaultParameterNameDiscoverer,我們發(fā)現(xiàn),他做的大體就是通過判斷standardReflectionAvailable這個值來走向不同分支流程:一個是走向剛才提到的利用JDK8編譯參數(shù)的StandardReflectionParameterNameDiscoverer另一個是走向了LocalVariableTableParameterNameDiscoverer

好,現(xiàn)在又出現(xiàn)了熟悉的StandardReflectionParameterNameDiscoverer了,那么我們返回去看吧,一會再看另一個分支的LocalVariableTableParameterNameDiscoverer。

我們回到StandardReflectionParameterNameDiscoverer中,再來看剛才那個-parameters編譯參數(shù),這是個什么黑科技?既然他是個編譯參數(shù),那么咱們不妨試著用它編譯一下咱們的代碼試一下吧。

我們將idea設置上-parameters編譯參數(shù)從新運行剛才的demo,發(fā)現(xiàn)這回的輸出結果是:

已經(jīng)能夠拿到參數(shù)的真實名稱了。那么,這個-parameters到底是什么呢:我們可以來看一下oracle官方提供的javac文檔

通過文檔可以看出加上這個參數(shù)后,編譯器會生成元數(shù)據(jù),從而使方法參數(shù)的反射能夠拿到參數(shù)的信息。
這個功能是jdk8的新特性,我們就不仔細展開了,詳情可以查看這兩篇文檔:
JDK 8 Features

JEP 118: Access to Parameter Names at Runtime

-parameters這個黑科技咱們已經(jīng)了解了,利用這個編譯參數(shù)是可以獲得方法參數(shù)的真實名稱的,但是這個參數(shù)是jdk8之后才有的,那么之前的版本如何獲得呢?我們繼續(xù)看Spring源代碼吧?,F(xiàn)在我們來看另一個分支:LocalVariableTableParameterNameDiscoverer,打開這個類:

其實看注釋就明白了,這個LocalVariableTableParameterNameDiscoverer是通過ASM library分析LocalVariableTable來實現(xiàn)獲得參數(shù)實際名稱的,ASM是一個第三方的字節(jié)碼操縱庫,用這個庫可以讀取寫入class文件,這個庫有很廣泛的應用,具體的我不展開介紹了。

我們重點說一下這個LocalVariableTable吧,這個LocalVariableTable是什么呢?我們不用文字來說明了,直接來看代碼吧:
我們這次不看源文件了,來直接看編譯后的class文件。

編譯后的class文件

idea打開Test1.class

然后在View菜單中點選Show Bytecode

在彈出窗口中,我們可以看到,idea以大綱的方式把class文件的信息列了出來,而在其中就有LocalVariableTable存在,而且在“LocalVariableTable”附近我們可以看到我們定義方法的參數(shù)的真實名稱?,F(xiàn)在我們也就明白了,對于8以下的jdk編譯環(huán)境,Spring是使用ASM來讀取class文件中LocalVariableTable信息從而獲得參數(shù)真實名稱的。
到此為止,我們已經(jīng)基本了解了Spring中自動綁定背后的黑科技了。

這里我還想繼續(xù)再多說一點,有關LocalVariableTable和Java class文件:class文件可以說是Java實現(xiàn)跨平臺特性的根本!不管在什么平臺下,只要編譯出來的class文件符合規(guī)范,虛擬機就能夠正常的執(zhí)行。了解一下class文件的相關知識其實對于理解各類class文件操縱庫以及基于class操縱的AOP等等編程模式的原理是很有幫助的,所以我們可以了解一下class文件是什么樣的結構的。想要了解class文件的結構,最權威的莫過于官方的《Java虛擬機規(guī)范了》,在Java虛擬機規(guī)范中,第四章是有關class文件結構的內容,我們可以大致過一遍。
通過閱讀,我們可以大致了解到class的結構:

A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit
quantities are constructed by reading in two, four, and eight consecutive 8-bit
bytes, respectively. Multibyte data items are always stored in big-endian order,
where the high bytes come first. In the Java SE platform, this format is supported
by interfaces java.io.DataInput and java.io.DataOutput and classes such as
java.io.DataInputStream and java.io.DataOutputStream.

class文件結構

class文件可以用一個結構來表示:

這個結構中每一項大致的含義我們來簡單說明一下吧(詳情請查看虛擬機規(guī)范):

開頭的magic u4叫做“魔數(shù)”,Java虛擬器通過讀取這個數(shù)來判斷當前文件是不是有效的u4代表它是無符號4byte,這個數(shù)始終應該是0xCAFEBABE;

minor_version、major_version分別是class文件的次版本主版本

u2 constant_pool_count 、cp_info constant_pool[constant_pool_count-1]代表常量池中項目數(shù)和代表了常量池本身;

u2 access_flags : 代表class訪問標記,例如:public protected;

u2 this_class : 代表放置類名在常量池中的索引;

u2 super_class : 代表父類名稱在常量池中的索引;

u2 interfaces_countu2 interfaces[interfaces_count]; 代表所實現(xiàn)的接口集合的大小,及接口集合本身;

u2 fields_countfield_info fields[fields_count]; 代表屬性集合大小以及屬性集合本身;

u2 methods_countmethod_info methods[methods_count]; 代表方法集合大小以及方法集合本身;

u2 attributes_countattribute_info attributes[attributes_count]; java class文件內部屬性信息集合大小和內部屬性信息集合本身。這里提一下,我們前面的提到的LocalVariableTable的信息就存儲在這里。

總結

到了這里我們大致回顧一下吧,我們從嘗試解決反射獲得方法參數(shù)真實名稱開始,了解了Java編譯參數(shù)、Spring自動綁定相關處理原理、jdk8編譯參數(shù)新特性、以及Java class文件的結構。通過這個過程,我們看到,就一個“自動綁定”這個平常都感覺不到它存在的小功能背后,還有這莫多深層次的技術在里面,由此可見,Spring之所以如此強大而且易用,離不開各類底層技術的支持,這就讓我想起以前看到過的一位技術博主的標語:“只有深入,方能淺出”,想想確實是這個道理。

以上就是論java如何通過反射獲得方法真實參數(shù)名及擴展研究的詳細內容,更多關于java反射獲得真實參數(shù)名的資料請關注腳本之家其它相關文章!

相關文章

  • Java中java.lang.ClassCastException異常原因及解決方法

    Java中java.lang.ClassCastException異常原因及解決方法

    大家好,本篇文章主要講的是Java中java.lang.ClassCastException異常原因及解決方法,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • Java多線程父線程向子線程傳值問題及解決

    Java多線程父線程向子線程傳值問題及解決

    文章總結了5種解決父子之間數(shù)據(jù)傳遞困擾的解決方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDecorator、ExecutorConfig、RequestContextHolder+TaskDecorator、MDC+TaskDecorator和InheritableThreadLocal
    2025-02-02
  • JAVA值傳遞和引用傳遞方式

    JAVA值傳遞和引用傳遞方式

    文章總結:在Java中,處理不可變集合時,直接修改操作會拋出異常,正確的做法是使用可變集合類型,如ArrayList,或者通過流操作(stream().filter())來實現(xiàn)修改,理解Java方法參數(shù)的傳遞方式(值傳遞)是關鍵,這決定了如何正確地修改對象的狀態(tài)
    2024-11-11
  • Rabbitmq消息推送功能實現(xiàn)示例

    Rabbitmq消息推送功能實現(xiàn)示例

    rabbitMQ為異步消息處理提出了一個很好的解決方案,它是一個非常好用的消息中間件。主要解決當生產(chǎn)者大量產(chǎn)生數(shù)據(jù)時,消費者無法快速消費的問題。這個時候需要一個中間層,保存這個數(shù)據(jù),rabbitMQ是一個很好的解決方案
    2022-12-12
  • Java實現(xiàn)abc字符串排列組合

    Java實現(xiàn)abc字符串排列組合

    這篇文章主要為大家詳細介紹了JAVA實現(xiàn)abc字符串的排列組合,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Springboot 限制IP訪問指定的網(wǎng)址實現(xiàn)

    Springboot 限制IP訪問指定的網(wǎng)址實現(xiàn)

    本文主要介紹了Springboot 限制IP訪問指定的網(wǎng)址實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • java實現(xiàn)停車場系統(tǒng)

    java實現(xiàn)停車場系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)停車場系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • java的各種類型轉換全部匯總(推薦)

    java的各種類型轉換全部匯總(推薦)

    下面小編就為大家?guī)硪黄猨ava的各種類型轉換全部匯總(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • springboot返回html和jsp的方法示例

    springboot返回html和jsp的方法示例

    這篇文章主要介紹了springboot返回html和jsp的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • java微信server錄音下載到自己server

    java微信server錄音下載到自己server

    這篇文章主要為大家詳細介紹了java微信server錄音下載到自己server的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05

最新評論