如何获得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文件做了加密混淆吧局部变量表里面的变量名改变了,那就没法获得源码级别的参数名了。
时间: 2024-08-05 15:01:23

如何获得JVM执行过程中调用的方法名的相关文章

多线程:子线程执行过程中调用主线程

直接在子线程中调用方法,线程的ID为3,通过Post则为1 执行结果: 2018-09-13 11:21:11:1735 : 主线程:1 2018-09-13 11:21:16:0583 : 子线程:3 2018-09-13 11:21:16:0739 : ShowForm:1发送失败! 2018-09-13 11:21:16:1051 : ShowForm:3发送失败! public class TestClass { private SynchronizationContext mainTh

只能在执行Render() 的过程中调用 RegisterForEventValidation;

October 17, 2008  3:28 PMMarch 29, 2013  8:28 PM Aillo 编程   0 Comments 在实现"将GridView中的数据导出到Excel中"的时候出现了如下错误: 用户代码未处理 InvalidOperationException 只能在执行 Render() 的过程中调用 RegisterForEventValidation: EnableEventValidation属性是 .NET Framework 2.0 中是新增的属性

只能在执行 Render() 的过程中调用 RegisterForEventValidation(RegisterForEventValidation can only be called during Render();

只能在执行 Render() 的过程中调用 RegisterForEventValidation(RegisterForEventValidation can only be called during Render(); 当用GridView导出Execl的时候,会发生只能在执行 Render() 的过程中调用 RegisterForEventValidation的错误提示.有两种方法可以解决以上问题:1.修改web.config(不推荐)<pages enableEventValidatio

Error 之 只能在执行Render() 的过程中调用 RegisterForEventValidation;

在实现"将GridView中的数据导出到Excel中"的时候出现了如下错误: 用户代码未处理 InvalidOperationException 只能在执行 Render() 的过程中调用 RegisterForEventValidation: EnableEventValidation属性是 .NET Framework 2.0 中是新增的属性,默认的情况下该属性的值为true:通过这个新增的功能ASP.NET会检查 POST方法中的所带的参数,如果认为不合法,就会抛出异常.这个设计

"只能在执行Render()的过程中调用RegisterForEventValidation" 解决方案

开发中遇到令人蛋疼的问题: 只能在执行Render()的过程中调用RegisterForEventValidation 当出现的异常的提示: 异常详细信息: System.InvalidOperationException:只能在执行Render()的过程中调用RegisterForEventValidation: 不要伤心,下面是解决办法: 出现这个异常,解决问题只需要在<%@ Page %> 指令中加上 EnableEventValidation="false" &qu

问题:只能在执行 Render() 的过程中调用 RegisterForEventValidation;结果:只能在执行 Render() 的过程中调用 RegisterForEventValidation

只能在执行 Render() 的过程中调用 RegisterForEventValidation 当在导出Execl或Word的时候,会发生只能在执行 Render() 的过程中调用 RegisterForEventValidation的错误提示.下面的2中方法是在网上找到的,没有应用:1.修改web.config(不推荐) <pages enableEventValidation ="false" ></pages> 2.直接在导出Execl的页面修改 <

Effective C++ 条款九、十 绝不在构造和析构过程中调用virtual函数|令operator=返回一个reference to *this

  1.当在一个子类当中调用构造函数,其父类构造函数肯定先被调用.如果此时父类构造函数中有一个virtual函数,子类当中也有,肯定执行父类当中的virtual函数,而此时子类当中的成员变量并未被初始化,所以无法调用子类与之对应的函数.即为指向虚函数表的指针vptr没被初始化又怎么去调用派生类的virtual函数呢?析构函数也相同,派生类先于基类被析构,又如何去找派生类相应的虚函数? 2.做法:将子类的某个函数改为non-virtual,然后在子类构造函数中传递参数给父类函数.然后父类的构造函数

作为项目管理者如何避免项目的延期与执行过程中的加班问题

作为一个项目管理者,最担心的事情就是项目的不能够如期完成:作为一个项目实施者,最担心的是无休无止的加班.项目的不能够如期完成直接导致的是用户或者甲方对公司信誉.能力等各个方面的怀疑与否定,项目实施过程中的无休无止的加班导致的则是员工上班积极性.员工思维等哥哥方面的问题.可以说,这两个方面直接决定着该项目的成败,那么,作为一个项目管理者,应该如何去避免该类的事情发生或者尽可能的减少该事情的发生呢?下面我们分析一下. 1.计划不清 作为一个项目的管理者,项目执行时最怕的就是对该项目没有一个较好的规划

Effective C++ Item 9 绝不在构造和析构过程中调用virtual函数

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层) 示例: <pre name="code" class="cpp">#include <iostream> #include <string> using namespace std; c