猿论
首发于猿论
字节码实战--手写一个btrace

字节码实战--手写一个btrace

简易的btrace需求

偶现的方法执行慢,我们是可以用jstack捕捉到的,但是慢到什么地步却是不一定知道的,现在就需要在不重启应用的情况下,获取方法执行的时间。


需求特点

  1. 应用不重启
  2. 获取方法执行时间


技术选型

想要打印出时间,起码想到的是aop的方式。常规的方法是必须重启应用才能加的,典型的就是spring的aop,如果允许修改代码的话可以使用动态代理,或者自己写死到代码里。


操作方案

动态代理或者写死到代码

这种情况对代码的入侵太高了,如果要去掉这个功能,修改代码也是很麻烦的。


spring aop

这个需要依赖spring框架来做。可以不修改代码,但是不能做到动态生效。


javaagent

javaagent在1.6之后可以使用远程attach的方式,进行类的重新转化。这个是满足需求的。这个不了解的话可以去网上查查看。


字节码增强技术

方式选择好以后,那么关键点就是如何选择修改字节码的框架。

javassist

javassist是相对好用的,不过他想要在一个方法前后加代码,是通过方法包装来的,就是命名一个新的方法名和现在执行的方法名一样,然后把旧的方法重新命名。流程如下:
转化前:

 public void hello(){
        int a=0;
}

转化后

public void hello(){
    xxx
    helloxx();
    xxx
}

 public void helloxx(){
        int a=0;
}


这种情况是transform的做法,但是retransform有不能新增方法的限制。jdk的文档描述如下
> The retransformation must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.


asm

asmapi操作比较麻烦。但是可以直接修改方法体的内容。
转化前:

 public void hello(){
        int a=0;
}

转化后:

 public void hello(){
        xxx
        int a=0;
        xxx
}


asm的做法也有两种方式,一种是增加方法调用,然后把传递的值保存在threadlocal里,另外一种就是把所有的内容写到方法里中。这两种都可以满足需求,第一种实现方式还简单一些,不用新增本地变量。


实现方式

修改字节码的代码比较枯燥,所有直接附上代码地址,此次使用的是asm增加方法局部变量的方式做的,这样的demo网上博客没有,asm的手册中也没有这样的例子,如果有兴趣的可以去看看。
github.com/xpbob/lightT


作者:xpbob

链接:imooc.com/article/detai

来源:慕课网

本文原创发布于慕课网 ,转载请注明出处,谢谢合作


推荐阅读:

【官方】手记栏目认证作者招募,长期有效,随时报名!_慕课手记

有奖征文005期 |人生路上得一良师,是何感受?

前端干货合集(6.27)

主流分布式架构的风流韵事

Docker轻松入门(详解)

编辑于 2018-07-08

文章被以下专栏收录

    “只整码,不整事”。程序员界依据所用的不同语言划分不同帮派,会出现各种自黑互黑现象,这个专栏希望能进行正向的知识传播和分享,不相互拆台,不互怼,和谐友好进行交流。