zoukankan      html  css  js  c++  java
  • 如何获得JVM执行过程中调用的方法名

    这应该分成两个问题,1.如何获取参数值. 2.如何获取参数名, 

    1.如何获取参数值。这个是运行时的数据,你程序处理下获取就好了。比如写一个代理

    2.参数名是在编译的时候就写入到class文件的。,而这些方法的参数在class中就是一个局部变量。class对于局部变量的定义和存储专门有张表。
    单纯通过反射目前好像没有办法,通过字节码解析倒是可以
    比如下面代码

    public static void staticMethod(String args1, String args2) {
    }

    局部变量表:
    [pc: 0, pc: 1] local: args1 index: 0 type: java.lang.String
    [pc: 0, pc: 1] local: args2 index: 1 type: java.lang.String

    pc 0是每个字节码指令的程序计数器。[pc: 0, pc: 1] local: args1 index: 0 type: java.lang.String就是说在程序第0个指令到第1个指令的局部变量数组下标为0的变量类型是String变量名是args1.

    public static void nonStaticMethod(String args1, String args2) {
    }

    局部变量表;
    [pc: 0, pc: 1] local: this index: 0 type: asmtest.Test
    [pc: 0, pc: 1] local: args1 index: 1 type: java.lang.String
    [pc: 0, pc: 1] local: args2 index: 2 type: java.lang.String

    这个方法比上面的方法多了一个this。因为这个方法是非静态方法。

    所以如果要获取参数名需要解析字节码。这里给你一段代码使用ASM

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import org.objectweb.asm.ClassVisitor;
    import org.objectweb.asm.MethodVisitor;
    import org.objectweb.asm.Opcodes;
    import org.objectweb.asm.Type;

    public class ReadMethodArgNameClassVisitor extends ClassVisitor {

    public Map<String, List<String>> nameArgMap = new HashMap<String, List<String>>();

    public ReadMethodArgNameClassVisitor() {
    super(Opcodes.ASM5);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
    String signature, String[] exceptions) {
    Type methodType = Type.getMethodType(desc);
    int len = methodType.getArgumentTypes().length;
    List<String> argumentNames = new ArrayList<String>();
    nameArgMap.put(name, argumentNames);
    ReadMethodArgNameMethodVisitor visitor = new ReadMethodArgNameMethodVisitor(Opcodes.ASM5);
    visitor.argumentNames = argumentNames;
    visitor.argLen = len;
    return visitor;
    }
    }

    import java.util.List;

    import org.objectweb.asm.Label;
    import org.objectweb.asm.MethodVisitor;

    public class ReadMethodArgNameMethodVisitor extends MethodVisitor {

    public List<String> argumentNames;

    public int argLen;

    public ReadMethodArgNameMethodVisitor(int api) {
    super(api);
    }

    @Override
    public void visitLocalVariable(String name, String desc, String signature,
    Label start, Label end, int index) {
    if("this".equals(name)) {
    return;
    }
    if(argLen-- > 0) {
    argumentNames.add(name);
    }
    }

    }

    public class POJO {

    public void say(String message, int times){
    }

    }

    import java.io.IOException;
    import java.util.List;
    import java.util.Map.Entry;

    import org.objectweb.asm.ClassReader;

    public class Test {

    public static void main(String... args1) throws IOException {
    ClassReader cr = new ClassReader("POJO");
    ReadMethodArgNameClassVisitor classVisitor = new ReadMethodArgNameClassVisitor();
    cr.accept(classVisitor, 0);
    for(Entry<String, List<String>> entry : classVisitor.nameArgMap.entrySet()) {
    System.out.println(entry.getKey());
    for(String s : entry.getValue()) {
    System.out.println(" " + s);
    }
    }
    }

    }

    使用asm版本是

    <dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm-all</artifactId>
    <version>5.0.3</version>
    </dependency>

    这里存在一个隐患,如果有些class文件做了加密混淆吧局部变量表里面的变量名改变了,那就没法获得源码级别的参数名了。
  • 相关阅读:
    每日总结6.14
    每日总结6.13
    每日总结6.12
    每日总结6.11
    用户故事与敏捷方法阅读笔记4
    用户故事与敏捷方法阅读笔记3
    团队冲刺第一阶段燃尽图
    团队冲刺10
    智能物联网:将人工智能的力量带入物联网
    MyEclipse修改文件后Building workspace时间过长
  • 原文地址:https://www.cnblogs.com/beautiful-code/p/6264647.html
Copyright © 2011-2022 走看看