Classloader support matching classloader by class name. (#1428)

This commit is contained in:
Hollow Man 2020-08-14 00:55:44 -05:00 committed by GitHub
parent 92dd9a2fb0
commit 3dc3f36b9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 0 deletions

View File

@ -13,6 +13,7 @@ import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.handlers.Handler;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.ResultUtils;
import com.taobao.arthas.core.util.affect.RowAffect;
import com.taobao.middleware.cli.annotations.Description;
@ -56,6 +57,7 @@ public class ClassLoaderCommand extends AnnotatedCommand {
private Logger logger = LoggerFactory.getLogger(ClassLoaderCommand.class);
private boolean isTree = false;
private String hashCode;
private String classLoaderClass;
private boolean all = false;
private String resource;
private boolean includeReflectionClassLoader = true;
@ -70,6 +72,12 @@ public class ClassLoaderCommand extends AnnotatedCommand {
public void setTree(boolean tree) {
isTree = tree;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(shortName = "c", longName = "classloader")
@Description("The hash code of the special ClassLoader")
@ -113,6 +121,25 @@ public class ClassLoaderCommand extends AnnotatedCommand {
process.interruptHandler(new ClassLoaderInterruptHandler(this));
Instrumentation inst = process.session().getInstrumentation();
if (!all && hashCode == null && classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
hashCode = "" + Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
ClassLoaderModel classloaderModel = new ClassLoaderModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(classloaderModel);
process.end(-1, "Found more than one classloader by class name, please specify classloader with '-c <classloader hash>'");
return;
} else {
process.end(-1, "Can not find classloader by class name: " + classLoaderClass + ".");
return;
}
}
if (all) {
processAllClasses(process, inst);
} else if (hashCode != null && resource != null) {

View File

@ -4,6 +4,7 @@ import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderSta
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* @author gongdewei 2020/4/21
@ -20,6 +21,9 @@ public class ClassLoaderModel extends ResultModel {
private Map<String, ClassLoaderStat> classLoaderStats;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public ClassLoaderModel() {
}
@ -90,4 +94,22 @@ public class ClassLoaderModel extends ResultModel {
this.classLoaderStats = classLoaderStats;
return this;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public ClassLoaderModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public ClassLoaderModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
}

View File

@ -22,6 +22,12 @@ public class ClassLoaderView extends ResultView<ClassLoaderModel> {
@Override
public void draw(CommandProcess process, ClassLoaderModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.getClassSet() != null) {
drawAllClasses(process, result.getClassSet());
}

View File

@ -16,6 +16,7 @@ classloader
|[t]|打印所有ClassLoader的继承树|
|[a]|列出所有ClassLoader加载的类请谨慎使用|
|`[c:]`|ClassLoader的hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|`[c: r:]`|用ClassLoader去查找resource|
|`[c: load:]`|用ClassLoader去加载指定的类|
@ -67,6 +68,18 @@ file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
Affect(row-cnt:9) cost in 3 ms.
```
*注意* hashcode是变化的需要先查看当前的ClassLoader信息提取对应ClassLoader的hashcode。
对于只有唯一实例的ClassLoader可以通过class name指定使用起来更加方便
```bash
$ classloader --classLoaderClass sun.misc.Launcher$AppClassLoader
file:/private/tmp/arthas-demo.jar
file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
Affect(row-cnt:9) cost in 3 ms.
```
#### 使用ClassLoader去查找resource
```bash

View File

@ -13,6 +13,7 @@ View hierarchy, urls and classes-loading info for the class-loaders.
|[t]|print classloader's hierarchy|
|[a]|list all the classes loaded by all the classloaders (use it with great caution since the output can be huge)|
|[c:]|print classloader's hashcode|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[c: r:]`|using ClassLoader to search resource|
|`[c: load:]`|using ClassLoader to load class|
@ -64,6 +65,18 @@ file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
Affect(row-cnt:9) cost in 3 ms.
```
Note that the hashcode changes, you need to check the current ClassLoader information first, and extract the hashcode corresponding to the ClassLoader.
For ClassLoader with only unique instance, it can be specified by class name, which is more convenient to use:
```bash
$ classloader --classLoaderClass sun.misc.Launcher$AppClassLoader
file:/private/tmp/arthas-demo.jar
file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
Affect(row-cnt:9) cost in 3 ms.
```
#### Use the classloader to load resource
```bash