有什么我们再生产遇到一个紧急的问题,此时不方便重新发布服务或者发布的版本没有生效,此时就可以使用Arthas这个救火队员来临时修改线上代码,非常强大。今天我们就来演示一下它是如何使用的。
- 定位到需要修改的类
- 将定位到的.class文件反编译成.java文件
- 修改.java文件
- 将修改后的.java文件重新编译成.class文件
- 将新的.class文件重新加载到JVM中
接下来我们详细看下它的工作步骤:安装arthas
1.定位需要修改的类
使用sc命令,sc就是search class的缩写
//定位 NameController,支持通配符,-d打印类的详细信息,更多信息请看官网命令
sc -d *NameController*
复制这个classLoaderHash,接下来要用
2.将定位到的.class文件反编译成.java文件
使用jad命令
//-c: 类所属 ClassLoader 的 hashcode
//--source-only: 默认情况下,反编译结果里会带有`ClassLoader`信息,通过`--source-only`选项,可以只打印源代码
// /root/arthasTest/NameController.java 指的是反编译后的源文件放在哪里,并制定文件名
jad -c 2e5d6d97 --source-only com.qiuguan.boot.controller.NameController > /root/arthasTest/NameController.java
成功之后,就可以在linux的 /root/arthasTest/
目录下看到 NameController.java
文件了。
3.修改反编译后的.java文件
最好是将反编译后的.java文件下载到本地再去修改,避免忘记导包
原来运行的代码:
//省略包
@RestController
public class NameController {
@GetMapping("name/{id}")
public String name(@PathVariable Integer id) {
System.out.println(id);
doTask();
return "name_" + id;
}
private void doTask(){
System.out.println("do Task.......");
}
}
反编译后修改的代码:
//省略包
@RestController
public class NameController {
@GetMapping("name/{id}")
public String name(@PathVariable Integer id) {
System.out.println(id);
doTask();
return "name_" + id;
}
private void doTask(){
System.out.println("do Task start.......");
long start = System.currentTimeMillis();
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("do Task end, cost: " + (System.currentTimeMillis() - start) / 1000);
}
}
4.将修改后的.java文件重新编译成.class文件
使用mc命令
// -c: 指定类加载器的hash值
mc -c 2e5d6d97 /root/arthasTest/NameController.java
5.将新的.class文件重新加载到JVM中
使用redefine 或者 retransform
redefine -c 2e5d6d97 /qiuguan_temp/tet/com/qiuguan/boot/controller/NameController.class
这里就成功将新的.class文件加载到JVM中了。
然后就是验证了,访问一下Controller(http://47.96.78.12:8080/name/78), 然后就以在arthas中看到打印信息,与我们修改后的一致。
好了,关于使用Arthas动态修改代码就介绍到这里,更多功能请移步Arthas官网