1. 程式人生 > >Spring 中 java 獲取方法引數名稱

Spring 中 java 獲取方法引數名稱

一、介紹

在學習Spring ioc的時候,我們可以在Spring配置檔案中 對 物件構造器方法和例項方法按引數名稱進行注入,在我以前學習使用的時候,並沒有感覺有啥困難的,也一直以為java反射能夠獲取到方法的引數名稱,
但是在我簡單(spring ioc的原始碼細節太多了,有很多看不懂)看了spring ioc原始碼的部分時,發現Spring通過定義ParameterNameDiscoverer介面,來定義獲取引數名稱的方法,
這裡寫圖片描述

它的實現類:
這裡寫圖片描述

其中AspectJ相關的ParameterNameDiscover實現類原始碼並沒有看,準備學習到AOP的時候在來看。

二、獲取引數名稱的策略

1、使用jdk8,在jdk8中擴充的反射的API,在jdk8中提供了一個新的抽象類Executable,該類提供
了getParameters()方法,該方法可以用來獲取方法的引數名稱,並且Method和Constructor都繼承
了Executable。

這裡寫圖片描述

2、使用位元組碼框架,讀取每個方法棧幀中的區域性變量表,來獲取方法引數的名稱。

     Spring使用ASM位元組碼操作框架來獲取方法引數的名稱。
  使用ASM位元組碼框架,讀取類的class檔案。ASM框架底層已經將class檔案處理好,我們通過繼承
  ClassVisitor和MethodVisitor,並重寫部分方法,即可獲取到引數名稱。

     Spring中定義了LocalVariableTableParameterNameDiscoverer來實現這一過程,下面讓我們來
  看看該類的原始碼。

這裡寫圖片描述

該類實現了ParameterNameDiscover介面中定義的2個方法,分別對Method和Constructor方法進行處理。
並且將實際獲取引數名稱的實現轉交給inspectClass方法統一實現。

這裡寫圖片描述

inspectClass方法中主要步驟如下:
    1、以位元組流的形式讀取class檔案
    2、使用ASM的ClassReader處理解析class檔案,併產生事件
    3、ClassReader.accept接受一個ClassVisitor(ParameterNameDiscoveringVistor)來消
      費ClassReader產生的事件

這裡寫圖片描述

ClassVisitor中定義了一些方法來處理與之對應的Class檔案中的各個部分,

Class檔案結構分為以下幾個部分:

這裡寫圖片描述
而VisitMethod方法則是對應Class檔案中的方法表集合,visitMehod方法會返回一個MethodVisitor用
來處理Class檔案中方法表集合中的每個方法,如果我們要獲取方法引數名稱,則需要自定
義MethodVisitor的部分實現。

這裡寫圖片描述

這裡有一點漏講了,在computeLvtSlotIndices()方法中有個Type[]型別的paramTypes
(其中Type型別應該是ASM框架裡的型別),而computeLvtSlotIndices()方法在構造器中被呼叫,
在LocalVariableTableVisitor建構函式中parmTypes由Type.getArgumentTypes(desc)產生

那麼這個建構函式中的desc引數到底是什麼尼?
其實你去看下,介紹Class位元組碼結構的書籍就知道了(主要看下欄位表集合和方法表集合)

這裡寫圖片描述

這裡寫圖片描述

在欄位表和方法表中有個descriptor_index,它是描述符,
對於欄位:用來描述欄位型別
對於方法:用來描述引數列表和返回值
比如一個java型別 String[][] a; 則被描述為:[[Ljava/lang/String;
比如一個java方法 public String[][] get(String[] str,int name),則被描述為:
( [[Ljava/lang/String;I)[[Ljava/lang/String;

其對應關係如圖:
這裡寫圖片描述

多維陣列則對應多個 [

LocalVariableTableVisitor建構函式引數中的desc就是方法表的描述符,而Type.getArgumentTypes(desc)則就是簡單的解析這個描述符的方法而已

到此結束
對於ASM位元組碼框架,我只是簡單學習了下,大概學習瞭如何從中獲取,對於通過ASM生成位元組碼還沒有這個水平。
對於位元組碼結構的熟悉程度:只能算了解,需要去查。
而這些:對於我這個業務程式設計師來說:如果不改變,永遠都用不到,真是可悲。

相關推薦

Spring java 獲取方法引數名稱

一、介紹 在學習Spring ioc的時候,我們可以在Spring配置檔案中 對 物件構造器方法和例項方法按引數名稱進行注入,在我以前學習使用的時候,並沒有感覺有啥困難的,也一直以為java反射能夠獲取到方法的引數名稱, 但是在我簡單(spring ioc的

java獲取方法引數名的若干實踐

文章首發於我的個人部落格網站梧桐和風的部落格,歡迎關注。 前言 我們知道java可以通過反射得到方法名、引數型別等資訊。但我們似乎不能直接得到方法的引數名。而在一些場景中,比如構建自己的MVC框架時,我們也想像Spring MVC一樣,根據引數名獲取

使用Java8獲取方法引數名稱

在Java 8之前的版本,程式碼編譯為class檔案後,方法引數的型別是固定的,但引數名稱卻丟失了,這和動態語言嚴重依賴引數名稱形成了鮮明對比。現在,Java 8開始在class檔案中保留引數名,給反射帶來了極大的便利。 示例: public class GetRunt

java 通過反射獲取方法引數列表名稱

說明             一般情況下是使用不到用反射來獲取引數列表名稱的,只要知道引數列表的型別就可以執行某一個引數了,因為引數名稱是給開發人員用的,執行時引數名稱不起作用。 所以 JDK 本身是沒有獲取引數列表名稱的。          如果要寫框架一類的東西,比

java獲取方法引數名稱

原來一直以為通過java的反射機制可以獲取到類的任何資訊。最近發現反射是無法獲取方法的引數名稱。但是有其他方式可以得到。 1.javassist:”Javassist是一個開源的分析、編輯和建立Java位元組碼的類庫。是由東京工業大學的數學和計算機科學系的 S

Spring AOP動態獲取函式引數的值

一個簡單的栗子,我們需要記錄一個訂單系統的訂單狀態流轉日誌。為了符合開閉原則,我們只能新加程式碼,隨之引入AOP。AOP的引入是這個功能實現的基礎。接著AOP的作用域是我們要思考的。最方便直觀的當然是註解。所以我們要自定義一個註解。作用於需要記錄日誌的方法上。然後,問題又來了,不通的函式,可能介面引數並不一致

spring 獲取方法引數簽名

最近在用CXF restful ,cxf3 集成了Validation, 但hibernate validation返回的異常資訊裡不能準確的顯示出方法引數簽名,只能以arg0 arg1來表示引數,對於我們的外部api來說我只能說hibernate做的真爛,spring 在

如何在java方法獲得當前方法名稱

部落格分類: JAVA 基礎JAVA方法名稱獲取類名訪問痕跡  在實際程式設計中,我們或許會在程式碼量比較大的情況下,給我們的程式碼做一些呼叫痕跡的東西 比如當前呼叫的是哪個類,類得哪個方法: 一、獲得當前類名: Java程式碼   this.getClass().

使用javassist獲取方法引數名稱列表

在實際工作中,有時候需要動態獲取某個類的方法引數名,一般反射機制是獲取不到的,需要藉助位元組碼工具才可以獲取到。package com.yanek.soa.test; import java.lang.reflect.Modifier; import javassist.

在SpringAOP如何獲取方法的引數值(實體類)以及引數

 廢話不多說直接上程式碼 引數對了效果就可以出來  返回值是一個map key 是引數名稱 value 是引數值, private static Map getFieldsName(Proceedi

java如何獲取方法引數

在java中,可以通過反射獲取到類、欄位、方法簽名等相關的資訊,像方法名、返回值型別、引數型別、泛型型別引數等,但是不能夠獲取方法的引數名。在實際開發場景中,有時需要根據方法的引數名做一些操作,比如像spring-mvc中,@RequestParam、@PathVariab

Spring Controller 獲取請求參數的方法筆記

-type 接收 turn public str json href mod oca 1、直接把表單的參數寫在Controller相應的方法的形參中,適用於get方式提交,不適用於post方式提交。若"Content-Type"="application/x-www-f

Asp.net MVC如何獲取控制器的名稱

tex 如何 route 控制 this .get data control str 如果在代碼中 當前controller、action的獲取RouteData.Route.GetRouteData(this.HttpContext).Values["controlle

java 獲取項目名稱

java 獲取項目名稱 //項目名稱 String path = request.getContextPath(); // 獲取傳輸協議 String http = request.getScheme(); // 獲取服務器名稱 String serverName = reque

java獲取本機名稱、IP、MAC地址和網卡名稱

sans mon any flex exc consola 獲取本地ip network log java獲取本機名稱、IP、MAC地址和網卡名稱摘自:https://blog.csdn.net/Dai_Haijiao/article/details/80364370 20

Java獲取本機名稱、本機MAC地址、IP地址

Java獲取本機名稱、本機MAC地址、IP地址 public class Test { public static void main(String[] args) throws Exception { InetAddre

spring boot restful api 方法引數 BindException 異常處理

  客戶端 post json 資料,api 方法 接收的引數綁定出現異常,丟擲  BindException 異常,可以按照如下的方式處理 1、方法引數中增加 BindingResult 引數,通過 bindingResult.hasErrors()

spring@Transactional的各個引數的意思和常見的事務陷阱 spring@Transactional的各個引數的意思和常見的事務陷阱

在service類前加上@Transactional,宣告這個service所有方法需要事務管理。每一個業務方法開始時都會開啟一個事務。 Spring預設情況下會對執行期例外(RunTimeException)進行事務回滾。這個例外是unchecked 如果遇到checked意外就不

jquery的ajax方法引數的用法和他的含義:

1.url:    要求為String型別的引數,(預設為當前頁地址)傳送請求的地址。 2.type:    要求為String型別的引數,請求方式(post或get)預設為get。注意其他http請求方法,例如put和delete也可以使用,但僅部分瀏覽器支援。 3.t

Spring Aop 修改目標方法引數和返回值

首先使用spring-aop需要在spring的配置檔案中假如 一、新建註解 @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented