JVM之字节码――字节码增强应用(一)_kenvifire-ChinaUnix博客

时间:2023-01-11 17:54:34

前面讲过了字节码增强的一些类库,接下来,我们在这些类库的基础上实现一些具体的应用,主要都是基于Javassist的应用。
1、性能测试 在一些特殊的场景下,我们需要对代码的性能进行统计,以发现耗费时间最长的地方,然后对代码进行优化。或者说是我们需要统计所有方法的执行时间和次数,看哪个方法的执行时间和次数最多。这里我们借助Javassist来实现这样的一个功能。当然,我们功能比较简单,只要给每个方法添加上输出执行时间的功能,具体的数据统计就不做了。 实现的方式很简单,在每个方法的开始和结束的地方分别计时,然后计算出时间差即可。 例如,我们有一个Hello.java类

点击(此处)折叠或打开

    public class Hello {
    public String test() throws Exception{
    Thread.currentThread ().sleep(1000);
    return "test";
    }

    }
我们要实现的功能就是修改该类,让它变成下面的样子:

点击(此处)折叠或打开

    public class Hello {
    public String test$Impl() throws Exception{
    return "test";
    }
    public String test( ) throws Exception{
    long start = System.currentTimeMillis();//统计开始时间
    Object result = test$Impl();//调用原方法
    long end = System.currentTimeMillis();//统计结束时间
    System.out.println("method test time used:" (end - start));//计算时间
    return result;
    }


    }
我们修改原来的方法test为test$Impl,把原来的test方法里添加上时间统计和对test$Impl的功能。知道了想要改成什么样子,那么代码就很好实现了。具体代码如下:

点击(此处)折叠或打开

    public static void modifyMethod(CtMethod method,CtClass clazz) throws Exception{

    //从原方法复制产生一个新的方法
    CtMethod newMethod = CtNewMethod. copy(method, clazz, null);

    //重命名原方法
    String methodName = method.getLongName();
    String oldName = method.getName() "$Impl";

    method.setName(oldName);
    StringBuilder body = new StringBuilder();
    body.append( "{long start = System.currentTimeMillis();" );

    //如果有返回值,则记录返回值,没有则不记录
    if(method.getReturnType()==CtClass. voidType){
    body.append( oldName "($$);");
    } else{
    body.append( "Object result = " oldName "($$);" );
    }
    body.append( " long end = System.currentTimeMillis();"
    "System.out.println(\"" methodName "\""
    "\"time used:\" " "(end - start));" );

    //如果有返回值,则添加return 语句
    if(method.getReturnType()==CtClass. voidType){
    body.append( "}");
    } else{
    body.append( "return result;}" );
    }
    newMethod.setBody(body.toString());
    clazz.addMethod(newMethod);


    }
我们通过一个modifyMethod方法来对要统计的方法进行修改,它实现的功能如下 1、通过CtNewMethod. copy复制原来的方法 2、把原来的方法重命名为以"$Impl"结尾的方法 3、修改复制的方法的方法体,加入时间统计的代码 上面代码里有个地方需要注意的就是要对返回值进行处理,如果原来的方法有返回值就要先记录下来,并在最后返回,如果没有则不用。

最后,运行我们的代码,结果如下: Hello.test()time used:1015 这样就可以获取到方法的执行时间了,再加上一下统计的功能就可以实现性能分析的功能了。