Arthas实践–jad/mc/redefine线上热更新
- jad命令反编译,然后可以用其它编译器,比如vim来修改源码
- mc命令来内存编译修改过的代码
- 用redefine命令加载新的字节码
比如一下简单的代码
@RestController public class TestController { private static Logger logger= LoggerFactory.getLogger(TestController.class); @GetMapping(value={"/user/{id}"}) public HashMap findArticleById(@PathVariable Integer id) { logger.info("id: {}", (Object)id); HashMap<String,Object> result=new HashMap<>(); result.put("name","jack"); result.put("age",30); if (id != null && id < 1) { throw new IllegalArgumentException("id < 1"); } return result; } }
请求会报错:接下来我们利用arthas进行热更新 不停服务的方式 修改代码
1.首先安装 curl -O https://alibaba.github.io/arthas/arthas-boot.jar
sc
查看JVM已加载的类信息
“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的 Class 信息,这个命令支持的参数有 [d]、[E]、[f] 和 [x:]。
2. [arthas@30842]$ sc -d *TestController | grep classLoaderHash利用sc 命令搜索jvm已经加装的TestController信息
mc
Memory Compiler/内存编译器,编译.java文件生成.class。
修改后的代码利用mc重新编译成class文件
@RestController
public class TestController { private static Logger logger= LoggerFactory.getLogger(TestController.class); @GetMapping(value={"/user/{id}"}) public HashMap findById(@PathVariable Integer id) { logger.info("id: {}", (Object)id); HashMap<String,Object> result=new HashMap<>(); result.put("name","jack"); result.put("age",30); if (id != null && id < 1) { result.put("code","-1"); return result; } return result; } }
2.[arthas@30842]$ mc -c 5197848c /root/project/TestController.java -d /root/project/ 利用mc编译生成的class文件
redefine
加载外部的.class文件,redefine jvm已加载的类
[arthas@30842]$ redefine /root/project/com/example/demo/TestController.class
redefine success, size: 1
redefine的限制
- 不允许新增加field/method
- 正在跑的函数,没有退出不能生效,比如下面新增加的System.out.println,只有run()函数里的会生效
当然在测试环境为了方便测试 节省打包流程可以通过这种方式快速验证 解决bug,线上环境慎用