Skip to content

Commit

Permalink
add classloader command scenario #847 (#1375)
Browse files Browse the repository at this point in the history
  • Loading branch information
HollowMan6 authored Aug 14, 2020
1 parent 52062ea commit 3d99c44
Show file tree
Hide file tree
Showing 14 changed files with 602 additions and 0 deletions.
2 changes: 2 additions & 0 deletions site/src/site/sphinx/classloader.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
classloader
===

[`classloader`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-classloader)

> 查看classloader的继承树,urls,类加载信息
`classloader` 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。
Expand Down
2 changes: 2 additions & 0 deletions site/src/site/sphinx/en/classloader.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
classloader
===========

[`classloader` online tutorial](https://arthas.aliyun.com/doc/arthas-tutorials?language=en&id=command-classloader)

View hierarchy, urls and classes-loading info for the class-loaders.

`classloader` can search and print out the URLs for a specified resource from one particular classloader. It is quite handy when analyzing `ResourceNotFoundException`.
Expand Down
16 changes: 16 additions & 0 deletions tutorials/katacoda/command-classloader-cn/arthas-boot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@




在新的`Terminal 2`里,下载`arthas-boot.jar`,再用`java -jar`命令启动:

`wget https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar`{{execute T2}}

`arthas-boot``Arthas`的启动程序,它启动后,会列出所有的Java进程,用户可以选择需要诊断的目标进程。

选择第一个进程,输入 `1`{{execute T2}} ,再`Enter/回车`

Attach成功之后,会打印Arthas LOGO。输入 `help`{{execute T2}} 可以获取到更多的帮助信息。

![Arthas Boot](/arthas/scenarios/common-resources/assets/arthas-boot.png)
183 changes: 183 additions & 0 deletions tutorials/katacoda/command-classloader-cn/classloader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@

> 查看classloader的继承树,urls,类加载信息
`classloader` 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。

可以让指定的classloader去getResources,打印出所有查找到的resources的url。对于`ResourceNotFoundException`比较有用。


### 参数说明

|参数名称|参数说明|
|---:|:---|
|[l]|按类加载实例进行统计|
|[t]|打印所有ClassLoader的继承树|
|[a]|列出所有ClassLoader加载的类,请谨慎使用|
|`[c:]`|ClassLoader的hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|`[c: r:]`|用ClassLoader去查找resource|
|`[c: load:]`|用ClassLoader去加载指定的类|

### 使用参考

先访问一个jsp网页,触发jsp的加载: https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com/hello

### 列出所有ClassLoader

`classloader -l`{{execute T2}}

```bash
$ classloader -l
name loadedCount hash parent
BootstrapClassLoader 2724 null null
com.taobao.arthas.agent.ArthasClassloader@411ce1ab 2009 411ce1ab sun.misc.Launcher$ExtClassLoader@7494e528
com.taobao.arthas.agent.ArthasClassloader@22ae1234 1253 22ae1234 sun.misc.Launcher$ExtClassLoader@7494e528
org.apache.jasper.servlet.JasperLoader@65361d9a 1 65361d9a TomcatEmbeddedWebappClassLoader
context: ROOT
delegate: true
----------> Parent Classloader:
org.springframework.boot.loader.LaunchedURLClassLoader@1be6f5c3

TomcatEmbeddedWebappClassLoader 0 8546cd5 org.springframework.boot.loader.LaunchedURLClassLoader@1be6f5c3
context: ROOT
delegate: true
----------> Parent Classloader:
org.springframework.boot.loader.LaunchedURLClassLoader@1be6f5c3

org.springframework.boot.loader.LaunchedURLClassLoader@1be6f5c3 5416 1be6f5c3 sun.misc.Launcher$AppClassLoader@3d4eac69
sun.misc.Launcher$AppClassLoader@3d4eac69 45 3d4eac69 sun.misc.Launcher$ExtClassLoader@7494e528
sun.misc.Launcher$ExtClassLoader@7494e528 4 7494e528 null
```

* TomcatEmbeddedWebappClassLoader 加载的class数量是0,所以在spring boot embedded tomcat里,它只是一个空壳,所有的类加载都是`LaunchedURLClassLoader`完成的

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

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

```bash
$ classloader -c 65361d9a
```

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

```bash
$ classloader --classLoaderClass org.apache.jasper.servlet.JasperLoader
```
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。

### 列出ClassLoader里加载的所有类

列出上面的`org.apache.jasper.servlet.JasperLoader`加载的类:

`classloader -a --classLoaderClass org.apache.jasper.servlet.JasperLoader`{{execute T2}}

```bash
$ classloader -a --classLoaderClass org.apache.jasper.servlet.JasperLoader
hash:1698045338, org.apache.jasper.servlet.JasperLoader@65361d9a
org.apache.jsp.jsp.hello_jsp
```

### 查看类的classloader层次

`sc -d org.apache.jsp.jsp.hello_jsp`{{execute T2}}

### 查看ClassLoader树


`classloader -t`{{execute T2}}

```
$ classloader -t
+-BootstrapClassLoader
+-sun.misc.Launcher$ExtClassLoader@28cbbddd
+-com.taobao.arthas.agent.ArthasClassloader@8c25e55
+-sun.misc.Launcher$AppClassLoader@55f96302
+-org.springframework.boot.loader.LaunchedURLClassLoader@1be6f5c3
+-TomcatEmbeddedWebappClassLoader
context: ROOT
delegate: true
----------> Parent Classloader:
org.springframework.boot.loader.LaunchedURLClassLoader@1be6f5c3
+-org.apache.jasper.servlet.JasperLoader@21ae0fe2
```

### 查看URLClassLoader实际的urls

比如上面查看到的spring LaunchedURLClassLoader的 hashcode是`1be6f5c3`,可以通过`-c`参数来指定classloader,或者直接使用`--classLoaderClass`,从而查看URLClassLoader实际的urls:

`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader`{{execute T2}}

```
$ classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader
jar:file:/home/scrapbook/tutorial/demo-arthas-spring-boot.jar!/BOOT-INF/classes!/
jar:file:/home/scrapbook/tutorial/demo-arthas-spring-boot.jar!/BOOT-INF/lib/spring-boot-starter-aop-1.5
.13.RELEASE.jar!/
...
```

### 加载指定ClassLoader里的资源文件

查找指定的资源文件: `classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback-spring.xml`{{execute T2}}

```
$ classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r logback-spring.xml
jar:file:/home/scrapbook/tutorial/demo-arthas-spring-boot.jar!/BOOT-INF/classes!/logback-spring.xml
```
也可以尝试查找类的class文件:

`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r java/lang/String.class`{{execute T2}}

```bash
$ classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -r java/lang/String.class
jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/String.class
```

### 尝试加载指定的类

比如用上面的spring LaunchedURLClassLoader 尝试加载 `ch.qos.logback.classic.spi.StackTraceElementProxy`

首先使用`sc ch.qos.logback.classic.spi.StackTraceElementProxy`{{execute T2}}查看,可发现未加载:

```bash
Affect(row-cnt:0) cost in 18 ms.
```

因而使用spring LaunchedURLClassLoader 尝试加载:

`classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --load ch.qos.logback.classic.spi.StackTraceElementProxy`{{execute T2}}

```bash
$ classloader --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --load ch.qos.logback.classic.spi.StackTraceElementProxy
load class success.
class-info ch.qos.logback.classic.spi.StackTraceElementProxy
code-source file:/home/scrapbook/tutorial/demo-arthas-spring-boot.jar!/BOOT-INF/lib/logback-classic-1.
1.11.jar!/
name ch.qos.logback.classic.spi.StackTraceElementProxy
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name StackTraceElementProxy
modifier public
annotation
interfaces java.io.Serializable
super-class +-java.lang.Object
class-loader +-org.springframework.boot.loader.LaunchedURLClassLoader@5674cd4d
+-sun.misc.Launcher$AppClassLoader@70dea4e
+-sun.misc.Launcher$ExtClassLoader@56a96482
classLoaderHash 5674cd4d
```

再次使用`sc ch.qos.logback.classic.spi.StackTraceElementProxy`{{execute T2}}查看,发现已经加载:

```bash
ch.qos.logback.classic.spi.StackTraceElementProxy
Affect(row-cnt:1) cost in 19 ms.
```
12 changes: 12 additions & 0 deletions tutorials/katacoda/command-classloader-cn/finish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

在“classloader”中,我们演示了了Arthas的classloader命令。如果有更多的技巧或者使用疑问,欢迎在Issue里提出。

* Issues: https://github.com/alibaba/arthas/issues
* 文档: https://arthas.aliyun.com/doc


如果您在使用Arthas,请让我们知道,您的使用对我们非常重要:[查看](https://github.com/alibaba/arthas/issues/111)

欢迎关注公众号,获取Arthas项目的信息,源码分析,案例实践。

![Arthas公众号](/arthas/scenarios/common-resources/assets/qrcode_gongzhonghao.jpg)
45 changes: 45 additions & 0 deletions tutorials/katacoda/command-classloader-cn/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"title": "Arthas classloader命令",
"description": "Arthas classloader命令",
"difficulty": "精通者",
"time": "10-20 分钟",
"details": {
"steps": [
{
"title": "启动demo",
"text": "start-demo.md"
},
{
"title": "启动arthas-boot",
"text": "arthas-boot.md"
},
{
"title": "classloader命令",
"text": "classloader.md"
}
],
"intro": {
"text": "intro.md"
},
"finish": {
"text": "finish.md"
},
"assets": {
"host01": []
}
},
"environment": {
"uilayout": "terminal",
"showdashboard": true,
"dashboards": [
{
"name": "Web Port 80",
"port": 80
}
]
},
"backend": {
"imageid": "java",
"environmentsprotocol": "http"
}
}
23 changes: 23 additions & 0 deletions tutorials/katacoda/command-classloader-cn/intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@



![Arthas](https://arthas.aliyun.com/doc/_images/arthas.png)

`Arthas` 是Alibaba开源的Java诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。

`Arthas` 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。

当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?

本教程会以一个普通的Spring Boot应用为例,演示classloader命令。

* Github: https://github.com/alibaba/arthas
* 文档: https://arthas.aliyun.com/doc/
14 changes: 14 additions & 0 deletions tutorials/katacoda/command-classloader-cn/start-demo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@




下载`demo-arthas-spring-boot.jar`,再用`java -jar`命令启动:

`wget https://github.com/hengyunabc/spring-boot-inside/raw/master/demo-arthas-spring-boot/demo-arthas-spring-boot.jar
java -jar demo-arthas-spring-boot.jar`{{execute T1}}

`demo-arthas-spring-boot`是一个很简单的spring boot应用,源代码:[查看](https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-arthas-spring-boot)

启动之后,可以访问80端口: https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com

![Demo Web](/arthas/scenarios/common-resources/assets/demo-web.png)
16 changes: 16 additions & 0 deletions tutorials/katacoda/command-classloader-en/arthas-boot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@




In the new `Terminal 2`, download `arthas-boot.jar` and start with the `java -jar` command:

`wget https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar`{{execute T2}}

`arthas-boot` is the launcher for `Arthas`. It lists all the Java processes, and the user can select the target process to be diagnosed.

Select the first process, type `1`{{execute T2}} ,then type `Enter`

After the Attach is successful, Arthas LOGO is printed. Enter `help`{{execute T2}} for more help.

![Arthas Boot](/arthas/scenarios/common-resources/assets/arthas-boot.png)
Loading

0 comments on commit 3d99c44

Please sign in to comment.