偶现的方法执行慢,我们是可以用jstack捕捉到的,但是慢到什么地步却是不一定知道的,现在就需要在不重启应用的情况下,获取方法执行的时间。
想要打印出时间,起码想到的是aop的方式。常规的方法是必须重启应用才能加的,典型的就是spring的aop,如果允许修改代码的话可以使用动态代理,或者自己写死到代码里。
这种情况对代码的入侵太高了,如果要去掉这个功能,修改代码也是很麻烦的。
这个需要依赖spring框架来做。可以不修改代码,但是不能做到动态生效。
javaagent在1.6之后可以使用远程attach的方式,进行类的重新转化。这个是满足需求的。这个不了解的话可以去网上查查看。
方式选择好以后,那么关键点就是如何选择修改字节码的框架。
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.
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