一、介绍

在学习Spring ioc的时候,我们可以在Spring配置文件中 对 对象构造器方法和实例方法按参数名称进行注入,在我以前学习使用的时候,并没有感觉有啥困难的,也一直以为java反射能够获取到方法的参数名称,

但是在我简单(spring ioc的源码细节太多了,有很多看不懂)看了spring ioc源码的部分时,发现Spring通过定义ParameterNameDiscoverer接口,来定义获取参数名称的方法,

Method java 参数值 获取 java获取参数名称_字节码

它的实现类:

Method java 参数值 获取 java获取参数名称_获取参数_02

其中AspectJ相关的ParameterNameDiscover实现类源码并没有看,准备学习到AOP的时候在来看。

二、获取参数名称的策略

1、使用jdk8,在jdk8中扩充的反射的API,在jdk8中提供了一个新的抽象类Executable,该类提供
了getParameters()方法,该方法可以用来获取方法的参数名称,并且Method和Constructor都继承
了Executable。

Method java 参数值 获取 java获取参数名称_java_03

2、使用字节码框架,读取每个方法栈帧中的局部变量表,来获取方法参数的名称。

     Spring使用ASM字节码操作框架来获取方法参数的名称。
  使用ASM字节码框架,读取类的class文件。ASM框架底层已经将class文件处理好,我们通过继承
  ClassVisitor和MethodVisitor,并重写部分方法,即可获取到参数名称。

     Spring中定义了LocalVariableTableParameterNameDiscoverer来实现这一过程,下面让我们来
  看看该类的源码。

Method java 参数值 获取 java获取参数名称_获取参数_04

该类实现了ParameterNameDiscover接口中定义的2个方法,分别对Method和Constructor方法进行处理。
并且将实际获取参数名称的实现转交给inspectClass方法统一实现。

Method java 参数值 获取 java获取参数名称_获取参数_05

inspectClass方法中主要步骤如下:
    1、以字节流的形式读取class文件
    2、使用ASM的ClassReader处理解析class文件,并产生事件
    3、ClassReader.accept接受一个ClassVisitor(ParameterNameDiscoveringVistor)来消
      费ClassReader产生的事件

Method java 参数值 获取 java获取参数名称_字节码_06

ClassVisitor中定义了一些方法来处理与之对应的Class文件中的各个部分,

Class文件结构分为以下几个部分:

Method java 参数值 获取 java获取参数名称_java_07


而VisitMethod方法则是对应Class文件中的方法表集合,visitMehod方法会返回一个MethodVisitor用

来处理Class文件中方法表集合中的每个方法,如果我们要获取方法参数名称,则需要自定

义MethodVisitor的部分实现。

Method java 参数值 获取 java获取参数名称_java_08

Method java 参数值 获取 java获取参数名称_java_09

这里有一点漏讲了,在computeLvtSlotIndices()方法中有个Type[]类型的paramTypes
(其中Type类型应该是ASM框架里的类型),而computeLvtSlotIndices()方法在构造器中被调用,
在LocalVariableTableVisitor构造函数中parmTypes由Type.getArgumentTypes(desc)产生

那么这个构造函数中的desc参数到底是什么尼?
其实你去看下,介绍Class字节码结构的书籍就知道了(主要看下字段表集合和方法表集合)

Method java 参数值 获取 java获取参数名称_字节码_10

Method java 参数值 获取 java获取参数名称_Method java 参数值 获取_11

在字段表和方法表中有个descriptor_index,它是描述符,
对于字段:用来描述字段类型
对于方法:用来描述参数列表和返回值
比如一个java类型 String[][] a; 则被描述为:[[Ljava/lang/String;
比如一个java方法 public String[][] get(String[] str,int name),则被描述为:
( [[Ljava/lang/String;I)[[Ljava/lang/String;

其对应关系如图:

Method java 参数值 获取 java获取参数名称_java_12

多维数组则对应多个 [

LocalVariableTableVisitor构造函数参数中的desc就是方法表的描述符,而Type.getArgumentTypes(desc)则就是简单的解析这个描述符的方法而已

到此结束
对于ASM字节码框架,我只是简单学习了下,大概学习了如何从中获取,对于通过ASM生成字节码还没有这个水平。
对于字节码结构的熟悉程度:只能算了解,需要去查。
而这些:对于我这个业务程序员来说:如果不改变,永远都用不到,真是可悲。