mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
Fix classloaderhash problem in advance tutorial (#1417)
Signed-off-by: hollowman6 <hollowman186@vip.qq.com>
This commit is contained in:
@@ -80,12 +80,13 @@ $ classloader -t
|
||||
|
||||
+-org.apache.jasper.servlet.JasperLoader@21ae0fe2
|
||||
```
|
||||
注意:请使用你的classLoaderHash值覆盖 `<classLoaderHash>` ,然后手动执行下面相关命令:
|
||||
|
||||
### 列出ClassLoader的urls
|
||||
|
||||
比如上面查看到的spring LaunchedURLClassLoader的 hashcode是`1be6f5c3`,可以通过`-c`参数来列出它的所有urls:
|
||||
|
||||
`classloader -c 1be6f5c3`{{execute T2}}
|
||||
`classloader -c <classLoaderHash>`
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3
|
||||
@@ -97,7 +98,7 @@ jar:file:/home/scrapbook/tutorial/demo-arthas-spring-boot.jar!/BOOT-INF/lib/spri
|
||||
|
||||
### 加载指定ClassLoader里的资源文件
|
||||
|
||||
查找指定的资源文件: `classloader -c 1be6f5c3 -r logback-spring.xml`{{execute T2}}
|
||||
查找指定的资源文件: `classloader -c <classLoaderHash> -r logback-spring.xml`
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3 -r logback-spring.xml
|
||||
@@ -108,7 +109,7 @@ $ classloader -c 1be6f5c3 -r logback-spring.xml
|
||||
|
||||
比如用上面的spring LaunchedURLClassLoader 尝试加载 `java.lang.String` :
|
||||
|
||||
`classloader -c 1be6f5c3 --load java.lang.String`{{execute T2}}
|
||||
`classloader -c <classLoaderHash> --load java.lang.String`
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3 --load java.lang.String
|
||||
|
||||
@@ -45,11 +45,15 @@ $ sc -d *UserController | grep classLoaderHash
|
||||
|
||||
可以发现是 spring boot `LaunchedURLClassLoader@1be6f5c3` 加载的。
|
||||
|
||||
请记下你的classLoaderHash,后面需要使用它。在这里,它是 `1be6f5c3`。
|
||||
|
||||
注意:请使用你的classLoaderHash值覆盖 `<classLoaderHash>` ,然后手动执行这些命令:
|
||||
|
||||
### mc
|
||||
|
||||
保存好`/tmp/UserController.java`之后,使用`mc`(Memory Compiler)命令来编译,并且通过`-c`参数指定ClassLoader:
|
||||
|
||||
`mc -c 1be6f5c3 /tmp/UserController.java -d /tmp`{{execute T2}}
|
||||
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
|
||||
|
||||
```bash
|
||||
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
以`UserController`为例,它使用的是slf4j api,但实际使用到的logger系统是logback。
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'
|
||||
@Logger[
|
||||
serialVersionUID=@Long[5454405123156820674],
|
||||
FQCN=@String[ch.qos.logback.classic.Logger],
|
||||
@@ -28,15 +28,15 @@ $ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
### 获取logback实际加载的配置文件
|
||||
|
||||
|
||||
`ognl -c 1be6f5c3 '#map1=@org.slf4j.LoggerFactory@getLogger("root").loggerContext.objectMap, #map1.get("CONFIGURATION_WATCH_LIST")'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '#map1=@org.slf4j.LoggerFactory@getLogger("root").loggerContext.objectMap, #map1.get("CONFIGURATION_WATCH_LIST")'`{{execute T2}}
|
||||
|
||||
|
||||
### 使用classloader命令查找可能存在的logger配置文件
|
||||
|
||||
`classloader -c 1be6f5c3 -r logback-spring.xml`{{execute T2}}
|
||||
`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback-spring.xml`{{execute T2}}
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3 -r logback-spring.xml
|
||||
$ classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback-spring.xml
|
||||
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-arthas-spring-boot/target/demo-arthas-spring-boot-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/logback-spring.xml
|
||||
|
||||
Affect(row-cnt:1) cost in 13 ms.
|
||||
@@ -45,8 +45,8 @@ Affect(row-cnt:1) cost in 13 ms.
|
||||
|
||||
可以尝试加载容易冲突的文件:
|
||||
|
||||
`classloader -c 1be6f5c3 -r logback.xml`{{execute T2}}
|
||||
`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback.xml`{{execute T2}}
|
||||
|
||||
`classloader -c 1be6f5c3 -r log4j.properties`{{execute T2}}
|
||||
`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r log4j.properties`{{execute T2}}
|
||||
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ $ sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash
|
||||
|
||||
### 用ognl获取logger
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'
|
||||
@Logger[
|
||||
serialVersionUID=@Long[5454405123156820674],
|
||||
FQCN=@String[ch.qos.logback.classic.Logger],
|
||||
@@ -36,14 +36,14 @@ $ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
|
||||
### 单独设置UserController的logger level
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
|
||||
再次获取`UserController@logger`,可以发现已经是`DEBUG`了:
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'
|
||||
@Logger[
|
||||
serialVersionUID=@Long[5454405123156820674],
|
||||
FQCN=@String[ch.qos.logback.classic.Logger],
|
||||
@@ -62,5 +62,5 @@ $ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
|
||||
通过获取`root` logger,可以修改全局的logger level:
|
||||
|
||||
`ognl -c 1be6f5c3 '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
|
||||
|
||||
@@ -18,15 +18,36 @@ $ sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash
|
||||
classLoaderHash 1be6f5c3
|
||||
```
|
||||
|
||||
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
|
||||
|
||||
如果你使用`-c`,你需要手动输入hashcode:`-c <hashcode>`
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 @com.example.demo.arthas.user.UserController@logger
|
||||
```
|
||||
|
||||
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便:
|
||||
|
||||
```bash
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader @org.springframework.boot.SpringApplication@logger
|
||||
@Slf4jLocationAwareLog[
|
||||
FQCN=@String[org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog],
|
||||
name=@String[org.springframework.boot.SpringApplication],
|
||||
logger=@Logger[Logger[org.springframework.boot.SpringApplication]],
|
||||
]
|
||||
```
|
||||
|
||||
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
|
||||
### 获取静态类的静态字段
|
||||
|
||||
获取`UserController`类里的`logger`字段:
|
||||
|
||||
`ognl -c 1be6f5c3 @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
|
||||
还可以通过`-x`参数控制返回值的展开层数。比如:
|
||||
|
||||
`ognl -c 1be6f5c3 -x 2 @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -x 2 @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
|
||||
### 执行多行表达式,赋值给临时变量,返回一个List
|
||||
|
||||
|
||||
@@ -81,11 +81,13 @@ $ classloader -t
|
||||
+-org.apache.jasper.servlet.JasperLoader@21ae0fe2
|
||||
```
|
||||
|
||||
Note: Please replace `<classLoaderHash>` with your classLoaderHash above, then execute the related commands manually in the following steps:
|
||||
|
||||
### List the urls of the ClassLoader
|
||||
|
||||
For example, the hashcode of spring `LaunchedURLClassLoader` viewed above is `1be6f5c3`, and all its urls can be listed by the `-c` parameter:
|
||||
|
||||
`classloader -c 1be6f5c3`{{execute T2}}
|
||||
`classloader -c <classLoaderHash>`
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3
|
||||
@@ -97,7 +99,7 @@ jar:file:/home/scrapbook/tutorial/demo-arthas-spring-boot.jar!/BOOT-INF/lib/spri
|
||||
|
||||
### Load the resource file in the specified ClassLoader
|
||||
|
||||
Load the specified resource file: `classloader -c 1be6f5c3 -r logback-spring.xml`{{execute T2}}
|
||||
Load the specified resource file: `classloader -c <classLoaderHash> -r logback-spring.xml`
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3 -r logback-spring.xml
|
||||
@@ -108,7 +110,7 @@ $ classloader -c 1be6f5c3 -r logback-spring.xml
|
||||
|
||||
For example, try loading `java.lang.String` with spring LaunchedURLClassLoader :
|
||||
|
||||
`classloader -c 1be6f5c3 --load java.lang.String`{{execute T2}}
|
||||
`classloader -c <classLoaderHash> --load java.lang.String`
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3 --load java.lang.String
|
||||
|
||||
@@ -46,11 +46,15 @@ $ sc -d *UserController | grep classLoaderHash
|
||||
|
||||
It can be found that it is loaded by spring boot `LaunchedURLClassLoader@1be6f5c3`.
|
||||
|
||||
Please write down your classLoaderHash here, in the case here, it's `1be6f5c3`. It will be used in the future steps.
|
||||
|
||||
Note: Please replace `<classLoaderHash>` with your classLoaderHash above, then execute the related commands manually in the following steps:
|
||||
|
||||
### mc
|
||||
|
||||
After saving `/tmp/UserController.java`, compile with the `mc` (Memory Compiler) command and specify the ClassLoader with the `-c` option:
|
||||
|
||||
`mc -c 1be6f5c3 /tmp/UserController.java -d /tmp`{{execute T2}}
|
||||
`mc -c <classLoaderHash> /tmp/UserController.java -d /tmp`
|
||||
|
||||
```bash
|
||||
$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
|
||||
|
||||
@@ -7,11 +7,11 @@ In this case, show how to troubleshoot logger conflicts.
|
||||
|
||||
Take `UserController` as an example, it uses slf4j api, but the actual logger system used is logback.
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'
|
||||
@Logger[
|
||||
serialVersionUID=@Long[5454405123156820674],
|
||||
FQCN=@String[ch.qos.logback.classic.Logger],
|
||||
@@ -29,15 +29,15 @@ $ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
### Find the configuration file actually loaded by the logback
|
||||
|
||||
|
||||
`ognl -c 1be6f5c3 '#map1=@org.slf4j.LoggerFactory@getLogger("root").loggerContext.objectMap, #map1.get("CONFIGURATION_WATCH_LIST")'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '#map1=@org.slf4j.LoggerFactory@getLogger("root").loggerContext.objectMap, #map1.get("CONFIGURATION_WATCH_LIST")'`{{execute T2}}
|
||||
|
||||
|
||||
### Use the classloader command to find possible logger configuration files
|
||||
|
||||
`classloader -c 1be6f5c3 -r logback-spring.xml`{{execute T2}}
|
||||
`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback-spring.xml`{{execute T2}}
|
||||
|
||||
```
|
||||
$ classloader -c 1be6f5c3 -r logback-spring.xml
|
||||
$ classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback-spring.xml
|
||||
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-arthas-spring-boot/target/demo-arthas-spring-boot-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/logback-spring.xml
|
||||
|
||||
Affect(row-cnt:1) cost in 13 ms.
|
||||
@@ -46,8 +46,8 @@ You can know the specific source of the loaded configuration.
|
||||
|
||||
You can try to load files that are prone to conflict:
|
||||
|
||||
`classloader -c 1be6f5c3 -r logback.xml`{{execute T2}}
|
||||
`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback.xml`{{execute T2}}
|
||||
|
||||
`classloader -c 1be6f5c3 -r log4j.properties`{{execute T2}}
|
||||
`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r log4j.properties`{{execute T2}}
|
||||
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ $ sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash
|
||||
|
||||
### Use ognl command to get the logger
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'
|
||||
@Logger[
|
||||
serialVersionUID=@Long[5454405123156820674],
|
||||
FQCN=@String[ch.qos.logback.classic.Logger],
|
||||
@@ -36,14 +36,14 @@ The user can know that `UserController@logger` actually uses logback. Because `l
|
||||
|
||||
### Change the logger level of UserController
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
|
||||
Get `UserController@logger` again, the user can see that it is already `DEBUG`:
|
||||
|
||||
`ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'`{{execute T2}}
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger'
|
||||
@Logger[
|
||||
serialVersionUID=@Long[5454405123156820674],
|
||||
FQCN=@String[ch.qos.logback.classic.Logger],
|
||||
@@ -62,5 +62,5 @@ $ ognl -c 1be6f5c3 '@com.example.demo.arthas.user.UserController@logger'
|
||||
|
||||
By getting the `root` logger, the user can modify the global logger level:
|
||||
|
||||
`ognl -c 1be6f5c3 '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'`{{execute T2}}
|
||||
|
||||
|
||||
@@ -20,15 +20,35 @@ $ sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash
|
||||
classLoaderHash 1be6f5c3
|
||||
```
|
||||
|
||||
Please write down your classLoaderHash here since it's dynamic. In the case here, it's `1be6f5c3`.
|
||||
|
||||
if you use`-c`, you have to manually type hashcode by `-c <hashcode>`.
|
||||
|
||||
```bash
|
||||
$ ognl -c 1be6f5c3 @com.example.demo.arthas.user.UserController@logger
|
||||
```
|
||||
|
||||
For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use.
|
||||
|
||||
```bash
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader @org.springframework.boot.SpringApplication@logger
|
||||
@Slf4jLocationAwareLog[
|
||||
FQCN=@String[org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog],
|
||||
name=@String[org.springframework.boot.SpringApplication],
|
||||
logger=@Logger[Logger[org.springframework.boot.SpringApplication]],
|
||||
]
|
||||
```
|
||||
The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c <hashcode>` is dynamic.
|
||||
|
||||
### Get static fields of static classes
|
||||
|
||||
Get the `logger` field of the `UserController` class:
|
||||
|
||||
`ognl -c 1be6f5c3 @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
|
||||
Control the number of expansion layers of the return value with the `-x` parameter. such as:
|
||||
|
||||
`ognl -c 1be6f5c3 -x 2 @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
`ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -x 2 @com.example.demo.arthas.user.UserController@logger`{{execute T2}}
|
||||
|
||||
### Execute multi-line expressions
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Reference in New Issue
Block a user