Chinaunix首页 | 论坛 | 博客
  • 博客访问: 621688
  • 博文数量: 69
  • 博客积分: 1891
  • 博客等级: 上尉
  • 技术积分: 1359
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-20 23:38
文章分类

全部博文(69)

文章存档

2012年(46)

2011年(23)

分类: Java

2012-09-05 07:41:18

  前面讲过了字节码增强的一些类库,接下来,我们在这些类库的基础上实现一些具体的应用,主要都是基于Javassist的应用。

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

点击(此处)折叠或打开

  1. public class Hello {
  2.       public String test() throws Exception{
  3.              Thread.currentThread ().sleep(1000);
  4.              return "test";
  5.       }

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

点击(此处)折叠或打开

  1. public class Hello {
  2.        public String test$Impl() throws Exception{
  3.            return "test";
  4.       }
  5.         public String test( ) throws Exception{
  6.            long start = System.currentTimeMillis();//统计开始时间
  7.            Object result = test$Impl();//调用原方法
  8.            long end = System.currentTimeMillis();//统计结束时间
  9.            System.out.println("method test time used:" + (end - start));//计算时间
  10.            return result;
  11.       }
  12.                

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

点击(此处)折叠或打开

  1. public static void modifyMethod(CtMethod method,CtClass clazz) throws Exception{
  2.             
  3.              //从原方法复制产生一个新的方法
  4.             CtMethod newMethod = CtNewMethod. copy(method, clazz, null);
  5.             
  6.              //重命名原方法
  7.             String methodName = method.getLongName();
  8.             String oldName = method.getName()+ "$Impl";
  9.             
  10.             method.setName(oldName);
  11.             StringBuilder body = new StringBuilder();
  12.             body.append( "{long start = System.currentTimeMillis();" );

  13.              //如果有返回值,则记录返回值,没有则不记录
  14.              if(method.getReturnType()==CtClass. voidType){
  15.                   body.append( oldName+ "($$);");
  16.             } else{
  17.                   body.append( "Object result = " +oldName+"($$);" );
  18.             }
  19.             body.append( " long end = System.currentTimeMillis();"
  20.                         + "System.out.println(\"" +methodName+ "\""+
  21.                          "\"time used:\"+" + "(end - start));" );
  22.             
  23.              //如果有返回值,则添加return 语句
  24.              if(method.getReturnType()==CtClass. voidType){
  25.                   body.append( "}");
  26.             } else{
  27.                   body.append( "return result;}" );
  28.             }
  29.             newMethod.setBody(body.toString());
  30.             clazz.addMethod(newMethod);
  31.             
  32.             
  33.       }
 我们通过一个modifyMethod方法来对要统计的方法进行修改,它实现的功能如下
     1、通过CtNewMethod. copy复制原来的方法
     2、把原来的方法重命名为以"$Impl"结尾的方法
     3、修改复制的方法的方法体,加入时间统计的代码
     
     上面代码里有个地方需要注意的就是要对返回值进行处理,如果原来的方法有返回值就要先记录下来,并在最后返回,如果没有则不用。


最后,运行我们的代码,结果如下:
     Hello.test()time used:1015
   这样就可以获取到方法的执行时间了,再加上一下统计的功能就可以实现性能分析的功能了。
阅读(12315) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~