一、前言
一天下午正在摸鱼的时候,测试小姐姐走了过来求助,说是需要改动测试环境 mock 应用。但是这个应用一时半会又找不到源代码存在何处。但是测试小姐姐的活还是一定要帮,突然想起了 Arthas 可以热更新应用代码,按照网上的步骤,反编译应用代码,加上需要改动的逻辑,最后热更新成功。对此,测试小姐姐很满意,并表示下次会少提 Bug。
嘿嘿,以前一直对热更新背后原理很好奇,借着这个机会,研究一下热更新的原理。
二、Arthas 热更新
我们先来看下 Arthas 是如何热更新的。
详情参考:阿里巴巴Arthas实践--jad/mc/redefine线上热更新一条龙
假设我们现在有一个 HelloService
类,逻辑如下,现在我们使用 Arthas 热更新代码,让其输出 hello arthas
。
public class HelloService {
public static void main(String[] args) throws InterruptedException {
while (true){
TimeUnit.SECONDS.sleep(1);
hello();
}
}
public static void hello(){
System.out.println("hello world");
}
}
2.1、jad 反编译代码
首先运行 jad
命令反编译 class 文件获取源代码,运行命令如下:。
jad --source-only com.andyxh.HelloService > /tmp/HelloService.java
2.2、修改反编译之后的代码
拿到源代码之后,使用 VIM 等文本编辑工具编辑源代码,加入需要改动的逻辑。
2.3、查找 ClassLoader
然后使用 sc
命令查找加载修改类的 ClassLoader
,运行命令如下:
$ sc -d com.andyxh.HelloService | grep classLoaderHash
classLoaderHash 4f8e5cde
这里运行之后将会得到 ClassLoader
哈希值。
2.4、 mc
内存编译源代码
使用 mc 命令编译上一步修改保存的源代码,生成最终 class
文件。
$ mc -c 4f8e5cde /tmp/HelloService.java -d /tmp
Memory compiler output:
/tmp/com/andyxh/HelloService.class
Affect(row-cnt:1) cost in 463 ms.
2.5、redefine 热更新代码
运行 redefine 命令:
$ redefine /tmp/com/andyxh/HelloService.class
redefine success, size: 1
热更新成功之后,程序输出结果如下:
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3b344cf05606fdaba42a6f50c79b7222.png)
一般情况下,我们本地将会有源代码,上面的步骤我们可以进一步省略,我们可以先在自己 IDE 上改动代码,编译生成 class 文件。这样我们只需要运行 redefine
命令即可。也就是说实际上起到作用只是 redefine
。
三、 Instrumentation 与 attach 机制
Arthas 热更新功能看起来很神奇,实际上离不开 JDK 一些 API,分别为 instrument API 与 attach API。
3.1 Instrumentation
Jav