2.6 KiB
下面介绍通过jad
{{}} /mc
{{}} /redefine
{{}} 命令实现动态更新代码的功能。
目前,访问 /user/0 ,会返回 500 异常:
下面通过热更新代码,修改这个逻辑。
jad 反编译 UserController
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
{{execute T2}}
jad 反编译的结果保存在 /tmp/UserController.java
{{}} 文件里了。
再打开一个终端于 Tab 3
{{}} ,然后在 Tab3
{{}} 里用 sed
{{}} 来编辑/tmp/UserController.java
{{}} :
sed -i 's/throw new IllegalArgumentException("id < 1")/return new User(id, "name" + id)/g' /tmp/UserController.java
{{execute T3}}
使用 cat
{{}} 命令查看修改后的内容:
cat /tmp/UserController.java
{{exec}}
比如当 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);
}
mc
(Memory Compiler) 命令来编译加载 UserController 可以通过-c 指定 classLoaderHash 或者--classLoaderClass 参数指定 ClassLoader,这里为了操作连贯性使用 classLoaderClass
查询 UserController 类加载器
sc 查找加载 UserController 的 ClassLoader
回到 Tab 2
{{}} 里运行 sc -d *UserController | grep classLoaderHash
{{exec}}
classloader 查询类加载器名称
classloader -l
{{exec}} 查询所有的类加载器列表,UserController classLoaderHash
{{}} 值对应的类加载器为 org.springframework.boot.loader.LaunchedURLClassLoader
{{}}
mc 编译加载 UserController
保存到 /tmp/UserController.java
{{}} 之后可以使用 mc (Memory Compiler) 命令来编译
mc 指定 classloader 编译 UserController
mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
{{exec}}
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
{{}} 成功之后,再次访问 /user/0 ,结果是:
{
"id": 0,
"name": "name0"
}