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

简易的btrace需求

偶现的方法执行慢,咱们是能够用jstack捕捉到的,可是慢到什么地步倒是不必定知道的,如今就须要在不重启应用的状况下,获取方法执行的时间。java

需求特色

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

技术选型

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

操做方案

动态代理或者写死到代码

这种状况对代码的入侵过高了,若是要去掉这个功能,修改代码也是很麻烦的。github

spring aop

这个须要依赖spring框架来作。能够不修改代码,可是不能作到动态生效。spring

javaagent

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

字节码加强技术

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

javassist

javassist是相对好用的,不过他想要在一个方法先后加代码,是经过方法包装来的,就是命名一个新的方法名和如今执行的方法名同样,而后把旧的方法从新命名。流程以下: 转化前:代理

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

转化后code

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

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

这种状况是transform的作法,可是retransform有不能新增方法的限制。jdk的文档描述以下orm

The retransformation must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.rem

asm

asmapi操做比较麻烦。可是能够直接修改方法体的内容。 转化前:

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

转化后:

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

asm的作法也有两种方式,一种是增长方法调用,而后把传递的值保存在threadlocal里,另一种就是把全部的内容写到方法里中。这两种均可以知足需求,第一种实现方式还简单一些,不用新增本地变量。

实现方式

修改字节码的代码比较枯燥,全部直接附上代码地址,这次使用的是asm增长方法局部变量的方式作的,这样的demo网上博客没有,asm的手册中也没有这样的例子,若是有兴趣的能够去看看 https://github.com/xpbob/lightTrace

相关文章
相关标签/搜索