leolee1993atlive
8/29/2019 - 3:49 AM

使用Arthas进行Spring Boot热更新

下载启动arthas-boot

wget https://alibaba.github.io/arthas/arthas-boot.jar

java -jar arthas-boot.jar --target-ip 0.0.0.0

热更新代码

下面介绍通过jad/mc/redefine 命令实现动态更新代码的功能。

目前,访问 http://localhost/user/0 ,会返回500异常:

curl http://localhost/user/0

返回值如下

{"timestamp":1550223186170,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}

下面通过热更新代码,修改这个逻辑。

jad反编译UserController

jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java

jad反编译的结果保存在 /tmp/UserController.java文件里了。

然后用vim来编辑/tmp/UserController.java:

vim /tmp/UserController.java

比如当 user id 小于1时,也正常返回,不抛出异常:

@GetMapping(value={"/user/{id}"})
public User findUserById(@PathVariable Integer id) {
    logger.info("id: {}", (Object)id);
    if (id != null && id < 1) {
        return new User(id, "name" + id);
        // throw new IllegalArgumentException("id < 1");
    }
    return new User(id.intValue(), "name" + id);
}

sc查找加载UserController的ClassLoader

sc -d *UserController | grep classLoaderHash

终端显示如下

classLoaderHash 1be6f5c3

可以发现是 spring boot LaunchedURLClassLoader@1be6f5c3 加载的。

mc

保存好/tmp/UserController.java之后,使用mc(Memory Compiler)命令来编译,并且通过-c参数指定ClassLoader:

mc -c 1be6f5c3 /tmp/UserController.java -d /tmp

终端显示如下

Memory compiler output: /tmp/com/example/demo/arthas/user/UserController.class Affect(row-cnt:1) cost in 346 ms redefine

再使用redefine命令重新加载新编译好的UserController.class

redefine /tmp/com/example/demo/arthas/user/UserController.class

终端显示如下

redefine success, size: 1

热修改代码结果 redefine成功之后,再次访问 http://localhost/user/0 ,结果是:

{
  "id": 0,
  "name": "name0"
}