arthas/tutorials/katacoda/case-jad-mc-redefine-cn/case-jad-mc-redefine.md

3.0 KiB
Raw Blame History

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

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

curl http://localhost/user/0{{execute T3}}

{"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{{execute T2}}

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

再打开一个Terminal 3然后用vim来编辑/tmp/UserController.java

vim /tmp/UserController.java{{execute T3}}

比如当 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{{execute T2}}

$ sc -d *UserController | grep classLoaderHash
 classLoaderHash   1be6f5c3

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

注意hashcode是变化的需要先查看当前的ClassLoader信息提取对应ClassLoader的hashcode。

如果你使用-c你需要手动输入hashcode-c <hashcode>

对于只有唯一实例的ClassLoader可以通过--classLoaderClass指定class name使用起来更加方便.

--classLoaderClass 的值是ClassLoader的类名只有匹配到唯一的ClassLoader实例时才能工作目的是方便输入通用命令-c <hashcode>是动态变化的。

mc

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

mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp{{execute T2}}

$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms

也可以通过mc -c <classLoaderHash> /tmp/UserController.java -d /tmp,使用-c参数指定ClassLoaderHash:

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

redefine

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

redefine /tmp/com/example/demo/arthas/user/UserController.class{{execute T2}}

$ redefine /tmp/com/example/demo/arthas/user/UserController.class
redefine success, size: 1

热修改代码结果

redefine成功之后,再次访问 https://HOST_SUBDOMAIN-80-KATACODA_HOST.environments.katacoda.com/user/0 ,结果是:

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