如何通过反射获得方法的真实参数名(以及扩展研究)( 二 )


如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
打开DefaultParameterNameDiscoverer , 我们发现 , 他做的大体就是通过判断standardReflectionAvailable这个值来走向不同分支流程:一个是走向刚才提到的利用JDK8编译参数的StandardReflectionParameterNameDiscoverer另一个是走向了LocalVariableTableParameterNameDiscoverer
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
好 , 现在又出现了熟悉的StandardReflectionParameterNameDiscoverer了 , 那么我们返回去看吧 , 一会再看另一个分支的LocalVariableTableParameterNameDiscoverer 。
我们回到StandardReflectionParameterNameDiscoverer中 , 再来看刚才那个-parameters编译参数 , 这是个什么黑科技?既然它是个编译参数 , 那么咱们不妨试着用它编译一下咱们的代码试一下吧 。
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
我们将idea设置上-parameters编译参数从新运行刚才的demo , 发现这回的输出结果是:
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
已经能够拿到参数的真实名称了 。 那么 , 这个-parameters到底是什么呢:我们可以来看一下oracle官方提供的javac文档:
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
通过文档可以看出加上这个参数后 , 编译器会生成元数据 , 从而使方法参数的反射能够拿到参数的信息 。 这个功能是jdk8的新特性 , 我们就不仔细展开了 , 详情可以查看这两篇文档:JDK 8 Features
JEP 118: Access to Parameter Names at Runtime
-parameters这个黑科技咱们已经了解了 , 利用这个编译参数是可以获得方法参数的真实名称的 , 但是这个参数是jdk8之后才有的 , 那么之前的版本如何获得呢?我们继续看Spring源代码吧 。 现在我们来看另一个分支:LocalVariableTableParameterNameDiscoverer , 打开这个类:
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
其实看注释就明白了 , 这个LocalVariableTableParameterNameDiscoverer是通过ASM library分析LocalVariableTable来实现获得参数实际名称的 , ASM是一个第三方的字节码操纵库 , 用这个库可以读取写入class文件 , 这个库有很广泛的应用 , 具体的我不展开介绍了 。
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
我们重点说一下这个LocalVariableTable吧 , 这个LocalVariableTable是什么呢?我们不用文字来说明了 , 直接来看代码吧:我们这次不看源文件了 , 来直接看编译后的class文件 。 用idea打开Test1.class:
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
然后在View菜单中点选Show Bytecode:
如何通过反射获得方法的真实参数名(以及扩展研究)文章插图
在弹出窗口中 , 我们可以看到 , idea以大纲的方式把class文件的信息列了出来 , 而在其中就有LocalVariableTable存在 , 而且在“LocalVariableTable”附近我们可以看到我们定义方法的参数的真实名称 。 现在我们也就明白了 , 对于8以下的jdk编译环境 , Spring是使用ASM来读取class文件中LocalVariableTable信息从而获得参数真实名称的 。 到此为止 , 我们已经基本了解了Spring中自动绑定背后的黑科技了 。
这里我还想继续再多说一点 , 有关LocalVariableTable和Java class文件:class文件可以说是Java实现跨平台特性的根本!不管在什么平台下 , 只要编译出来的class文件符合规范 , 虚拟机就能够正常的执行 。 了解一下class文件的相关知识其实对于理解各类class文件操纵库以及基于class操纵的AOP等等编程模式的原理是很有帮助的 , 所以我们可以了解一下class文件是什么样的结构的 。 想要了解class文件的结构 , 最权威的莫过于官方的《Java虚拟机规范了》 , 在Java虚拟机规范中 , 第四章是有关class文件结构的内容 , 我们可以大致过一遍 。 通过阅读 , 我们可以大致了解到class的结构:
A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bitquantities are constructed by reading in two, four, and eight consecutive 8-bitbytes, 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 supportedby interfaces java.io.DataInput and java.io.DataOutput and classes such asjava.io.DataInputStream and java.io.DataOutputStream.