热更新代码
下面介绍通过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
文件里了。
再打开一个Terminal 3
,然后用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
$ 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
$ 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 /tmp/com/example/demo/arthas/user/UserController.class
redefine success, size: 1
-- 重新加载多个
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
获取容器并执行方法
tt -i 1000 -w 'target.getApplicationContext()'
$ tt -i 1000 -w 'target.getApplicationContext()'
@AnnotationConfigEmbeddedWebApplicationContext[
reader=@AnnotatedBeanDefinitionReader[org.springframework.context.annotation.AnnotatedBeanDefinitionReader@2e457641],
scanner=@ClassPathBeanDefinitionScanner[org.springframework.context.annotation.ClassPathBeanDefinitionScanner@6eb38026],
annotatedClasses=null,
basePackages=null,
]
Affect(row-cnt:1) cost in 439 ms.
获取spring bean,并调用函数
tt -i 1000 -w 'target.getApplicationContext().getBean("scheduledTask03").run()'
线程信息
1. 查看所有线程信息
thread
2. 查看具体线程的栈
查看线程ID 16的栈:
thread 16
3. 查看CPU使用率top n线程的栈
thread -n 3
查看5秒内的CPU使用率top n线程栈
thread -n 3 -i 5000
4. 查找线程是否有阻塞
thread -b
实时修改logger级别
1. 查看logger信息
logger
2. 修改logger级别
logger --name ROOT --level error