Arthas使用实战:不发布版本实现代码动态修改

1,926 阅读2分钟

gustavo-quepon-pF_2lrjWiJE-unsplash.jpg

有什么我们再生产遇到一个紧急的问题,此时不方便重新发布服务或者发布的版本没有生效,此时就可以使用Arthas这个救火队员来临时修改线上代码,非常强大。今天我们就来演示一下它是如何使用的。

  1. 定位到需要修改的类
  2. 将定位到的.class文件反编译成.java文件
  3. 修改.java文件
  4. 将修改后的.java文件重新编译成.class文件
  5. 将新的.class文件重新加载到JVM中

接下来我们详细看下它的工作步骤:安装arthas

1.定位需要修改的类

使用sc命令,sc就是search class的缩写

   //定位 NameController,支持通配符,-d打印类的详细信息,更多信息请看官网命令
   sc -d *NameController*

image.png

复制这个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

image.png

5.将新的.class文件重新加载到JVM中

使用redefine 或者 retransform

redefine -c  2e5d6d97 /qiuguan_temp/tet/com/qiuguan/boot/controller/NameController.class

image.png

这里就成功将新的.class文件加载到JVM中了。

然后就是验证了,访问一下Controller(http://47.96.78.12:8080/name/78), 然后就以在arthas中看到打印信息,与我们修改后的一致。

image.png

好了,关于使用Arthas动态修改代码就介绍到这里,更多功能请移步Arthas官网