Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How does java get the real parameter name of the method through reflection

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Today, I would like to share with you how java gets the real parameter name of the method through reflection. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article.

Example

Let's first take a look at such a small demo:

This is a very simple little demo, which is a simple class Test1,Test1 with a method test that contains two parameters. In the main method of Test1, the names of all parameters of the test method are obtained by injection and output to the standard stream. I thought the result of running this demo would get the parameter name of the method.

Result

Are you surprised? are you surprised? It's not what we agreed on.

Let's pause for a moment, put aside why reflection didn't get the correct value, and first talk about why I'm studying "getting the actual name of the method parameter through the reflection principle": because I want to emulate and implement the "auto-bind" feature in Spring MVC. As you know, there is an "auto-bind" feature in Spring MVC that automatically binds the value of the request parameter to the parameter of the @ RequestMapping method without any extra operation.

I think this function is very convenient, so I want to try to copy it myself and use it in the company's project development. My guess is that Spring gets the parameter name of the method through reflection and then goes to getParam (String name) in request to get the actual value and then binds it. So I tried to follow this line of thinking, and I encountered the problem that the reflection mentioned above could not get the actual name of the parameter. I asked the boss about this question, and after the boss learned my intention, after verification, I came to the conclusion that whether Spring MVC can use automatic binding normally is related to whether the java compiler adds the-g parameter when compiling, and this-g parameter represents whether the java compiler will output debugging information when compiling.

Debug

In other words, Spring obtains the real names of the parameters in the method by reading the debugging information generated by the java compiler. At this point, this problem is basically solved, but I still want to talk a little more about my follow-up learning results. Later I looked at Spring's processing logic for method parameters, that is, the underlying implementation of the "auto-bind" function.

So, what "cool techs" does Spring use to get the actual parameter names of the method? we might as well look at the source code of Spring and see how Spring is implemented.

Spring source code

Where does the massive source code of Spring look from? here, I solve it like this: I generally know that the operation to get the actual parameter name of the method should be related to the getParameters () method of Method, or this method may be called in its method. Well, we can use the "View call stack" function provided by idea to find out if this method has been called in Spring. Then the solution should be near the calling method.

We can see that, sure enough, there are methods in the org.spring package in the call stack, and two of them are methods of the StandardReflectionParameterNameDiscoverer class. In fact, we have found them. Looking at the name of this class, we can know that it deals with the Discoverer of ParameterName. (I would like to say a little more digression here, I personally very much agree with the fully named coding style of Spring. When you see the naming, you can see what this class is doing. So the code should be "self-describing")

Annotation

Okay, let's go back to the code and move on to this class: find that it has a brief comment:

The main idea is that this class is for the implementation of ParameterNameDiscoverer that uses the JDK8 based-parameters compilation parameter, so let's put aside what this-parameters parameter is all about.

Implement interface class

Continue to look up at the interface ParameterNameDiscoverer implemented by StandardReflectionParameterNameDiscoverer, and open the interface ParameterNameDiscoverer. Using the function of idea to view subclasses, we can see that it has a total of eight subclasses, including StandardReflectionParameterNameDiscoverer.

There is a subclass DefaultParameterNameDiscoverer with "Default" in its name. According to the general routine, the implementation with Default is the default, so let's give priority to it.

When we open DefaultParameterNameDiscoverer, we find that basically what he does is to go to different branch processes by judging the value of standardReflectionAvailable: one is to go to the StandardReflectionParameterNameDiscoverer using the JDK8 compilation parameters just mentioned, and the other is to go to LocalVariableTableParameterNameDiscoverer.

Well, now that we have the familiar StandardReflectionParameterNameDiscoverer again, let's go back and look at the LocalVariableTableParameterNameDiscoverer of another branch later.

Let's go back to StandardReflectionParameterNameDiscoverer and take a look at that-parameters compilation parameter, what kind of cool techs is this? Since it is a compilation parameter, we might as well try to compile our code with it.

We set the idea to-parameters compilation parameter to re-run the previous demo, and found that the output this time is:

You can already get the real name of the parameter. So, what exactly is this-parameters: let's take a look at the official javac documentation provided by oracle:

As can be seen from the documentation, after adding this parameter, the compiler generates metadata so that the reflection of the method parameter can get the parameter information.

This feature is a new feature of jdk8, so we won't expand it in detail. You can check out these two documents for details:

JDK 8 Features

JEP 118: Access to Parameter Names at Runtime

-parameters this cool techs we have learned that the real name of the method parameter can be obtained by using this compilation parameter, but this parameter does not exist until after jdk8, so how can the previous version be obtained? Let's move on to the Spring source code. Now let's look at another branch: LocalVariableTableParameterNameDiscoverer, open this class:

In fact, look at the notes to understand, this LocalVariableTableParameterNameDiscoverer is through the ASM library analysis of LocalVariableTable to achieve the actual name of the parameters, ASM is a third-party bytecode manipulation library, with this library can read and write class files, this library has a wide range of applications, I will not introduce the details.

Let's focus on this LocalVariableTable. What is this LocalVariableTable? Let's not use words to explain, let's just look at the code:

Instead of looking at the source file this time, let's look directly at the compiled class file.

Compiled class file

Open Test1.class with idea:

Then click Show Bytecode from the View menu:

In the pop-up window, we can see that idea outlines the information in the class file, where LocalVariableTable exists, and near "LocalVariableTable" we can see the real names of the parameters we define the method. Now we understand that for jdk compilation environments below 8, Spring uses ASM to read the LocalVariableTable information in the class file to get the real names of the parameters.

At this point, we have a basic understanding of cool techs behind automatic binding in Spring.

Here I would like to say a little more about LocalVariableTable and Java class files: class files can be said to be the foundation of Java's cross-platform features! No matter what platform it is, as long as the compiled class file conforms to the specification, the virtual machine can execute normally. Understanding the relevant knowledge of class files is actually very helpful to understand all kinds of class file manipulation libraries and the principles of programming modes such as AOP based on class manipulation, so we can understand the structure of class files. The most authoritative way to understand the structure of class files is the official "Java virtual machine specification". In the Java virtual machine specification, the fourth chapter is about the structure of class files, which we can go through.

By reading, we can get a general idea of the structure of 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 file structure

The class file can be represented by a structure:

Let's briefly explain the general meaning of each item in this structure (please refer to the virtual machine specification for details):

The first magic U4 is called a "magic number". The Java virtualizer reads this number to determine whether the current file is valid. U4 represents four unsigned byte, which should always be 0xCAFEBABE.

Minor_version and major_version are the minor and major versions of the class file, respectively

U2 constant_pool_count and cp_info constant_ Pool [constant _ pool_count-1] represent the number of items in the constant pool and represent the constant pool itself.

U2 access_flags: represents the class access tag, for example: public protected

U2 this_class: represents the index where the class name is placed in the constant pool

U2 super_class: represents the index of the parent class name in the constant pool

U2 interfaces_count; U2 interfaces [interfaces _ count]; represents the size of the implemented interface set, as well as the interface set itself

U2 fields_count; field_info fields [fields _ count]; represents the size of the attribute set and the attribute set itself

U2 methods_count; method_info methods [methods _ count]; represents the size of the method set and the method set itself

U2 attributes_count; attribute_info attributes [attributes _ count]; java class file internal attribute information collection size and internal attribute information collection itself. To mention here, the LocalVariableTable information we mentioned earlier is stored here.

This is all the content of the article "how to get the real parameter name of the method by java through reflection". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report