Fix classloaderhash problem in advance tutorial (#1417)

Signed-off-by: hollowman6 <hollowman186@vip.qq.com>
This commit is contained in:
hengyunabc
2020-08-12 11:15:30 +08:00
committed by GitHub
11 changed files with 90 additions and 38 deletions
@@ -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}}
+23 -2
View File
@@ -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}}
+22 -2
View File
@@ -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