Arthas 热更新代码
jad & mc & redefine
一条龙;更推荐jad & mc & retransform
;
命令说明
mc命令
Memory Compiler/内存编译器,编译.java文件生成.class。
可以通过-c
/--classLoaderClass
参数指定classloader,-d
参数指定输出目录
编译生成.class
文件之后,可以结合retransform
命令实现热更新代码。
retransform命令
加载外部的.class文件,retransform jvm已加载的类。
参考:Instrumentation#retransformClasses
retransform的限制
- 不允许新增加field/method
- 正在跑的函数,没有退出不能生效。
具体步骤
jad
命令反编译出内存中的字节码,生成 java 文件- 修改代码,使用
mc
命令内存编译新的 class 文件retransform
重新加载新的 class 文件
1. jad反编译
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
2. vim修改直接修改代码
vim /tmp/UserController.java
3. sc查找加载UserController的ClassLoader
sc -d *UserController | grep classLoaderHash
$ sc -d *UserController | grep classLoaderHash
classLoaderHash 728938a9
可以发现是 spring boot LaunchedURLClassLoader@728938a9
加载的。
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
如果你使用-c
,你需要手动输入hashcode:-c <hashcode>
对于只有唯一实例的ClassLoader可以通过--classLoaderClass
指定class name,使用起来更加方便.
-classLoaderClass
的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而c <hashcode>
是动态变化的。
4. mc编译生成class文件
# 唯一实例的ClassLoader
mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
# sc查找后指定
mc -c 728938a9 /tmp/UserController.java -d /tmp
output
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
5. retransform 加载class文件
retransform /tmp/com/example/demo/arthas/user/UserController.class
扩展信息
如何还原热更新代码?
查看 retransform entry
retransform -l
$ retransform -l
Id ClassName TransformCount LoaderHash LoaderClassName
1 com.example.dem 1 null null
o.arthas.user.U
serController
TransformCount 统计在 ClassFileTransformer#transform 函数里尝试返回 entry对应的 .class文件的次数,但并不表明transform一定成功。
删除指定 retransform entry
retransform -d 1
(需要指定 id)
删除所有 retransform entry
retransform --deleteAll
显式触发 retransform
retransform --classPattern com.example.demo.arthas.user.UserController
消除 retransform 的影响
- 删除这个类对应的 retransform entry (
retransform -d [id]
) - 重新触发 retransform (
retransform --classPattern xxxx class
)
如果不清除掉所有的 retransform entry,并重新触发 retransform ,则arthas stop时,retransform过的类仍然生效。
用jad可以确认是否已经被消除
热更新检查
复杂类更新不一定成功,可以在idea中ctrl+shift+f9
检查class能够热更新。
Arthas中 class/classloader 相关命令
- classloader - 查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource
- dump - dump 已加载类的 byte code 到特定目录
- jad - 反编译指定已加载类的源码
- mc - 内存编译器,内存编译
.java
文件为.class
文件 - redefine - 加载外部的
.class
文件,redefine 到 JVM 里 - retransform - 加载外部的
.class
文件,retransform 到 JVM 里 - sc - 查看 JVM 已加载的类信息
- sm - 查看已加载类的方法信息